bug 932037 - update harfbuzz to upstream release 0.9.23. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Fri, 01 Nov 2013 09:41:02 +0000
changeset 153010 7800ae2455bcc4fb722bdf1fe4ed99f11e9ddfaf
parent 153009 6e7f975dc8e77ae840ac22ed2b17c581632897d4
child 153011 9f04406171f728efec0a39c3383a36888ead2dab
push id25566
push userryanvm@gmail.com
push dateFri, 01 Nov 2013 18:40:05 +0000
treeherdermozilla-central@5bb07c1ae9f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs932037
milestone28.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 932037 - update harfbuzz to upstream release 0.9.23. r=jdaggett
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer-serialize.cc
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-buffer.h
gfx/harfbuzz/src/hb-common.h
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-layout.h
gfx/harfbuzz/src/hb-ot-map.cc
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.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-myanmar.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/test-buffer-serialize.cc
gfx/harfbuzz/src/test-size-params.cc
gfx/harfbuzz/src/test-would-substitute.cc
gfx/harfbuzz/src/test.cc
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -98,16 +98,18 @@ struct hb_buffer_t {
 
   /* 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 lookahead_len (void) const
+  { return 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,
@@ -129,16 +131,17 @@ struct hb_buffer_t {
 				   const hb_codepoint_t *glyph_data);
 
   HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
   /* Makes a copy of the glyph at idx to output and replace glyph_index */
   HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
   HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
   /* Copies glyph at idx to output but doesn't advance idx */
   HB_INTERNAL void copy_glyph (void);
+  HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
   /* Copies glyph at idx to output and advance idx.
    * If there's no output, just advance idx. */
   inline void
   next_glyph (void)
   {
     if (have_output)
     {
       if (unlikely (out_info != info || out_len != idx)) {
@@ -176,16 +179,17 @@ struct hb_buffer_t {
 
   /* Internal methods */
   HB_INTERNAL bool enlarge (unsigned int size);
 
   inline bool ensure (unsigned int size)
   { return likely (size < allocated) ? true : enlarge (size); }
 
   HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+  HB_INTERNAL bool shift_forward (unsigned int count);
 
   HB_INTERNAL void *get_scratch_buffer (unsigned int *size);
 
   inline void clear_context (unsigned int side) { context_len[side] = 0; }
 };
 
 
 #define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc
@@ -141,19 +141,19 @@ static unsigned int
       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;
+    if (buf_size > l)
     {
-      unsigned int l = p - b;
       memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
       *buf = '\0';
     } else
       return i - start;
   }
@@ -203,19 +203,19 @@ static unsigned int
 	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
 
       *p++ = '+';
       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
       if (pos->y_advance)
 	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
     }
 
-    if (buf_size > (p - b))
+    unsigned int l = p - b;
+    if (buf_size > l)
     {
-      unsigned int l = p - b;
       memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
       *buf_consumed += l;
       *buf = '\0';
     } else
       return i - start;
   }
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -134,16 +134,29 @@ hb_buffer_t::make_room_for (unsigned int
 
     out_info = (hb_glyph_info_t *) pos;
     memcpy (out_info, info, out_len * sizeof (out_info[0]));
   }
 
   return true;
 }
 
+bool
+hb_buffer_t::shift_forward (unsigned int count)
+{
+  assert (have_output);
+  if (unlikely (!ensure (len + count))) return false;
+
+  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
+  len += count;
+  idx += count;
+
+  return true;
+}
+
 void *
 hb_buffer_t::get_scratch_buffer (unsigned int *size)
 {
   have_output = false;
   have_positions = false;
 
   out_len = 0;
   out_info = info;
@@ -340,16 +353,54 @@ hb_buffer_t::copy_glyph (void)
 {
   if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = info[idx];
 
   out_len++;
 }
 
+bool
+hb_buffer_t::move_to (unsigned int i)
+{
+  if (!have_output)
+  {
+    assert (i <= len);
+    idx = i;
+    return true;
+  }
+
+  assert (i <= out_len + (len - idx));
+
+  if (out_len < i)
+  {
+    unsigned int count = i - out_len;
+    if (unlikely (!make_room_for (count, count))) return false;
+
+    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
+    idx += count;
+    out_len += count;
+  }
+  else if (out_len > i)
+  {
+    /* Tricky part: rewinding... */
+    unsigned int count = out_len - i;
+
+    if (unlikely (idx < count && !shift_forward (count + 32))) return false;
+
+    assert (idx >= count);
+
+    idx -= count;
+    out_len -= count;
+    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
+  }
+
+  return true;
+}
+
 void
 hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
 {
   if (unlikely (out_info != info || out_len != idx)) {
     if (unlikely (!make_room_for (1, 1))) return;
     out_info[out_len] = info[idx];
   }
   out_info[out_len].codepoint = glyph_index;
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -167,20 +167,20 @@ 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 { /*< flags >*/
-  HB_BUFFER_FLAG_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_FLAG_DEFAULT			= 0x00000000u,
+  HB_BUFFER_FLAG_BOT				= 0x00000001u, /* Beginning-of-text */
+  HB_BUFFER_FLAG_EOT				= 0x00000002u, /* End-of-text */
+  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004u
 } 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);
@@ -270,20 +270,20 @@ void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
 
 
 /*
  * Serialize
  */
 
 typedef enum { /*< flags >*/
-  HB_BUFFER_SERIALIZE_FLAG_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_FLAG_DEFAULT		= 0x00000000u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS		= 0x00000001u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS		= 0x00000002u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES	= 0x00000004u
 } 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;
 
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -85,17 +85,17 @@ typedef union _hb_var_int_t {
   int8_t i8[4];
 } hb_var_int_t;
 
 
 /* hb_tag_t */
 
 typedef uint32_t hb_tag_t;
 
-#define HB_TAG(a,b,c,d) ((hb_tag_t)((((uint8_t)(a))<<24)|(((uint8_t)(b))<<16)|(((uint8_t)(c))<<8)|((uint8_t)(d))))
+#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
 #define HB_UNTAG(tag)   ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
 
 /* len=-1 means str is NUL-terminated. */
 hb_tag_t
 hb_tag_from_string (const char *str, int len);
 
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -89,17 +89,17 @@ hb_ft_get_glyph_h_advance (hb_font_t *fo
 {
   FT_Face ft_face = (FT_Face) font_data;
   int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
   FT_Fixed v;
 
   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
     return 0;
 
-  return v >> 10;
+  return (v + (1<<9)) >> 10;
 }
 
 static hb_position_t
 hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
 			   void *font_data,
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
@@ -107,17 +107,17 @@ hb_ft_get_glyph_v_advance (hb_font_t *fo
   int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT;
   FT_Fixed v;
 
   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
     return 0;
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
-  return -v >> 10;
+  return (-v + (1<<9)) >> 10;
 }
 
 static hb_bool_t
 hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
 			  void *font_data HB_UNUSED,
 			  hb_codepoint_t glyph HB_UNUSED,
 			  hb_position_t *x HB_UNUSED,
 			  hb_position_t *y HB_UNUSED,
@@ -413,18 +413,18 @@ hb_ft_font_create (FT_Face           ft_
 
   face = hb_ft_face_create (ft_face, destroy);
   font = hb_font_create (face);
   hb_face_destroy (face);
   hb_font_set_funcs (font,
 		     _hb_ft_get_font_funcs (),
 		     ft_face, (hb_destroy_func_t) _do_nothing);
   hb_font_set_scale (font,
-		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
-		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16,
+		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16);
   hb_font_set_ppem (font,
 		    ft_face->size->metrics.x_ppem,
 		    ft_face->size->metrics.y_ppem);
 
   return font;
 }
 
 
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -34,16 +34,17 @@
 #include "hb-set-private.hh"
 
 
 namespace OT {
 
 
 #define NOT_COVERED		((unsigned int) -1)
 #define MAX_NESTING_LEVEL	8
+#define MAX_CONTEXT_LENGTH	64
 
 
 
 /*
  *
  * OpenType Layout Common Table Formats
  *
  */
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -378,22 +378,24 @@ struct GDEF
 
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
    * Not to be confused with lookup_props which is very similar. */
   inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
   {
     unsigned int klass = get_glyph_class (glyph);
 
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+
     switch (klass) {
-    default:
-    case UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED;
+    default:			return 0;
     case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
     case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
-    case ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT;
     case MarkGlyph:
 	  klass = get_mark_attachment_type (glyph);
 	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
     }
   }
 
 
   protected:
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -385,37 +385,38 @@ struct MarkRecord
 struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
 {
   inline bool apply (hb_apply_context_t *c,
 		     unsigned int mark_index, unsigned int glyph_index,
 		     const AnchorMatrix &anchors, unsigned int class_count,
 		     unsigned int glyph_pos) const
   {
     TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
     const Anchor& mark_anchor = this + record.markAnchor;
     bool found;
     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
     /* If this subtable doesn't have an anchor for this base and this class,
      * return false such that the subsequent subtables have a chance at it. */
     if (unlikely (!found)) return TRACE_RETURN (false);
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
-    mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
-    glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
-    hb_glyph_position_t &o = c->buffer->cur_pos();
+    hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_lookback() = c->buffer->idx - glyph_pos;
+    o.attach_lookback() = buffer->idx - glyph_pos;
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
@@ -434,23 +435,24 @@ struct SinglePosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
-			     values, c->buffer->cur_pos());
+			     values, buffer->cur_pos());
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
   }
 
@@ -479,26 +481,27 @@ struct SinglePosFormat2
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     if (likely (index >= valueCount)) return TRACE_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
 			     &values[index * valueFormat.get_len ()],
-			     c->buffer->cur_pos());
+			     buffer->cur_pos());
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
@@ -583,34 +586,35 @@ struct PairSet
     }
   }
 
   inline bool apply (hb_apply_context_t *c,
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
   {
     TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
 
     const PairValueRecord *record = CastP<PairValueRecord> (array);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
     {
       /* TODO bsearch */
-      if (c->buffer->info[pos].codepoint == record->secondGlyph)
+      if (buffer->info[pos].codepoint == record->secondGlyph)
       {
 	valueFormats[0].apply_value (c->font, c->direction, this,
-				     &record->values[0], c->buffer->cur_pos());
+				     &record->values[0], buffer->cur_pos());
 	valueFormats[1].apply_value (c->font, c->direction, this,
-				     &record->values[len1], c->buffer->pos[pos]);
+				     &record->values[len1], buffer->pos[pos]);
 	if (len2)
 	  pos++;
-	c->buffer->idx = pos;
+	buffer->idx = pos;
 	return TRACE_RETURN (true);
       }
       record = &StructAtOffset<PairValueRecord> (record, record_size);
     }
 
     return TRACE_RETURN (false);
   }
 
@@ -654,20 +658,21 @@ struct PairPosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_buffer_t *buffer = c->buffer;
+    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
@@ -724,41 +729,42 @@ struct PairPosFormat2
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_buffer_t *buffer = c->buffer;
+    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int record_len = len1 + len2;
 
-    unsigned int klass1 = (this+classDef1).get_class (c->buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2).get_class (c->buffer->info[skippy_iter.idx].codepoint);
+    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c->font, c->direction, this,
-			      v, c->buffer->cur_pos());
+			      v, buffer->cur_pos());
     valueFormat2.apply_value (c->font, c->direction, this,
-			      v + len1, c->buffer->pos[skippy_iter.idx]);
+			      v + len1, buffer->pos[skippy_iter.idx]);
 
-    c->buffer->idx = skippy_iter.idx;
+    buffer->idx = skippy_iter.idx;
     if (len2)
-      c->buffer->idx++;
+      buffer->idx++;
 
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
@@ -870,39 +876,40 @@ struct CursivePosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
 
     /* We don't handle mark glyphs here. */
-    if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
+    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
 
-    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->cur().codepoint)];
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
     if (!this_record.exitAnchor) return TRACE_RETURN (false);
 
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
-    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint)];
+    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
     if (!next_record.entryAnchor) return TRACE_RETURN (false);
 
-    unsigned int i = c->buffer->idx;
+    unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
 
     hb_position_t entry_x, entry_y, exit_x, exit_y;
-    (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
-    (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
+    (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
 
-    hb_glyph_position_t *pos = c->buffer->pos;
+    hb_glyph_position_t *pos = buffer->pos;
 
     hb_position_t d;
     /* Main-direction adjustment */
     switch (c->direction) {
       case HB_DIRECTION_LTR:
 	pos[i].x_advance  =  exit_x + pos[i].x_offset;
 
 	d = entry_x + pos[j].x_offset;
@@ -945,17 +952,17 @@ struct CursivePosFormat1
     } else {
       pos[j].cursive_chain() = i - j;
       if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
 	pos[j].y_offset = exit_y - entry_y;
       else
 	pos[j].x_offset = exit_x - entry_x;
     }
 
-    c->buffer->idx = j;
+    buffer->idx = j;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
@@ -1017,33 +1024,34 @@ struct MarkBasePosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     do {
       if (!skippy_iter.prev ()) return TRACE_RETURN (false);
       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
-      if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
+      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
       skippy_iter.reject ();
     } while (1);
 
-    /* The following assertion is too strong, so we've disabled it. */
-    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
+    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
 
-    unsigned int base_index = (this+baseCoverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint);
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
@@ -1120,48 +1128,49 @@ struct MarkLigPosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
-    /* The following assertion is too strong, so we've disabled it. */
-    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
+    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
 
     unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (c->buffer->info[j].codepoint);
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
     if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
 
     const LigatureArray& lig_array = this+ligatureArray;
     const LigatureAttach& lig_attach = lig_array[lig_index];
 
     /* Find component to attach to */
     unsigned int comp_count = lig_attach.rows;
     if (unlikely (!comp_count)) return TRACE_RETURN (false);
 
     /* We must now check whether the ligature ID of the current mark glyph
      * is identical to the ligature ID of the found ligature.  If yes, we
      * can directly use the component index.  If not, we attach the mark
      * glyph to the last component of the ligature. */
     unsigned int comp_index;
-    unsigned int lig_id = get_lig_id (c->buffer->info[j]);
-    unsigned int mark_id = get_lig_id (c->buffer->cur());
-    unsigned int mark_comp = get_lig_comp (c->buffer->cur());
+    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     if (lig_id && lig_id == mark_id && mark_comp > 0)
-      comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1;
+      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
     else
       comp_index = comp_count - 1;
 
     return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
@@ -1235,32 +1244,33 @@ struct MarkMarkPosFormat1
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (c->buffer->cur().codepoint);
+    hb_buffer_t *buffer = c->buffer;
+    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
+    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
     if (!skippy_iter.prev ()) return TRACE_RETURN (false);
 
-    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); }
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
 
     unsigned int j = skippy_iter.idx;
 
-    unsigned int id1 = get_lig_id (c->buffer->cur());
-    unsigned int id2 = get_lig_id (c->buffer->info[j]);
-    unsigned int comp1 = get_lig_comp (c->buffer->cur());
-    unsigned int comp2 = get_lig_comp (c->buffer->info[j]);
+    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
 
     if (likely (id1 == id2)) {
       if (id1 == 0) /* Marks belonging to the same base. */
 	goto good;
       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
         goto good;
     } else {
       /* If ligature ids don't match, it may be the case that one of the marks
@@ -1268,17 +1278,17 @@ struct MarkMarkPosFormat1
       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
 	goto good;
     }
 
     /* Didn't match. */
     return TRACE_RETURN (false);
 
     good:
-    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (c->buffer->info[j].codepoint);
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
     if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
@@ -1429,22 +1439,16 @@ struct PosLookup : Lookup
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
   inline bool is_reverse (void) const
   {
     return false;
   }
 
-  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (true);
-  }
-
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     c->set_recurse_func (NULL);
     return TRACE_RETURN (dispatch (c));
   }
 
   template <typename set_t>
@@ -1586,19 +1590,17 @@ GPOS::position_finish (hb_font_t *font H
   /* Handle cursive connections */
   for (unsigned int i = 0; i < len; i++)
     fix_cursive_minor_offset (pos, i, direction);
 
   /* Handle attachments */
   for (unsigned int i = 0; i < len; i++)
     fix_mark_attachment (pos, i, direction);
 
-  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
+  _hb_buffer_deallocate_gsubgpos_vars (buffer);
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
 template <typename context_t>
 inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -32,22 +32,16 @@
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 
 namespace OT {
 
 
 struct SingleSubstFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
 	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
@@ -116,22 +110,16 @@ struct SingleSubstFormat1
   SHORT		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct SingleSubstFormat2
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -258,23 +246,16 @@ struct SingleSubst
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
 };
 
 
 struct Sequence
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    /* For len==0 we don't do anything, so it's harmless. */
-    return TRACE_RETURN (substitute.len <= 1);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->glyphs->add (substitute[i]);
   }
 
@@ -286,27 +267,27 @@ struct Sequence
       c->output->add (substitute[i]);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
 
-    unsigned int klass = c->buffer->cur().glyph_props() &
-			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     unsigned int count = substitute.len;
     if (count == 1) /* Special-case to make it in-place. */
     {
       c->replace_glyph (substitute.array[0]);
     }
     else
     {
       for (unsigned int i = 0; i < count; i++) {
-	set_lig_props_for_component (c->buffer->cur(), i);
+	_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
 	c->output_glyph (substitute.array[i], klass);
       }
       c->buffer->skip_glyph ();
     }
 
     return TRACE_RETURN (true);
   }
 
@@ -329,28 +310,16 @@ struct Sequence
   ArrayOf<GlyphID>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
 };
 
 struct MultipleSubstFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    /* Some tools generate MultipleSubst with each substitute having length 1!
-     * So, check them. */
-    unsigned int count = sequence.len;
-    for (unsigned int i = 0; i < count; i++)
-	if (!(this+sequence[i]).is_inplace (c))
-	  return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+sequence[iter.get_coverage ()]).closure (c);
     }
@@ -466,22 +435,16 @@ struct MultipleSubst
 };
 
 
 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
 
 struct AlternateSubstFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ())) {
 	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
 	unsigned int count = alt_set.len;
@@ -658,37 +621,36 @@ struct Ligature
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int count = component.len;
     if (unlikely (count < 1)) return TRACE_RETURN (false);
 
-    unsigned int end_offset = 0;
     bool is_mark_ligature = false;
     unsigned int total_component_count = 0;
 
+    unsigned int match_length = 0;
+    unsigned int match_positions[MAX_CONTEXT_LENGTH];
+
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
 			      NULL,
-			      &end_offset,
+			      &match_length,
+			      match_positions,
 			      &is_mark_ligature,
 			      &total_component_count)))
       return TRACE_RETURN (false);
 
-    /* Deal, we are forming the ligature. */
-    c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
-
     ligate_input (c,
 		  count,
-		  &component[1],
-		  match_glyph,
-		  NULL,
+		  match_positions,
+		  match_length,
 		  ligGlyph,
 		  is_mark_ligature,
 		  total_component_count);
 
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -792,22 +754,16 @@ struct LigatureSet
 		ligature;		/* Array LigatureSet tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, ligature);
 };
 
 struct LigatureSubstFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (false);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+ligatureSet[iter.get_coverage ()]).closure (c);
     }
@@ -946,22 +902,16 @@ struct ExtensionSubst : Extension<Extens
   typedef struct SubstLookupSubTable LookupSubTable;
 
   inline bool is_reverse (void) const;
 };
 
 
 struct ReverseChainSingleSubstFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
 
     count = backtrack.len;
@@ -1033,17 +983,19 @@ struct ReverseChainSingleSubstFormat1
 			 backtrack.len, (USHORT *) backtrack.array,
 			 match_coverage, this) &&
         match_lookahead (c,
 			 lookahead.len, (USHORT *) lookahead.array,
 			 match_coverage, this,
 			 1))
     {
       c->replace_glyph_inplace (substitute[index]);
-      c->buffer->idx--; /* Reverse! */
+      /* Note: We DON'T decrease buffer->idx.  The main loop does it
+       * for us.  This is useful for preventing surprises if someone
+       * calls us through a Context lookup. */
       return TRACE_RETURN (true);
     }
 
     return TRACE_RETURN (false);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
@@ -1189,23 +1141,16 @@ struct SubstLookup : Lookup
   inline bool is_reverse (void) const
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubstLookupSubTable::Extension))
       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
-  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    c->set_recurse_func (dispatch_recurse_func<hb_is_inplace_context_t>);
-    return TRACE_RETURN (dispatch (c));
-  }
-
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
     return TRACE_RETURN (dispatch (c));
   }
 
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1368,25 +1313,25 @@ struct GSUB : GSUBGPOS
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 
 void
 GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
-  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
-  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+  _hb_buffer_allocate_gsubgpos_vars (buffer);
 
   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
   unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++) {
-    buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
-    buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
+  for (unsigned int i = 0; i < count; i++)
+  {
+    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
+    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
+    buffer->info[i].syllable() = 0;
   }
 }
 
 void
 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
 {
 }
 
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -38,66 +38,16 @@ namespace OT {
 
 
 
 #define TRACE_DISPATCH(this) \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
-
-
-#ifndef HB_DEBUG_IS_INPLACE
-#define HB_DEBUG_IS_INPLACE (HB_DEBUG+0)
-#endif
-
-#define TRACE_IS_INPLACE(this) \
-	hb_auto_trace_t<HB_DEBUG_IS_INPLACE, bool> trace \
-	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "");
-
-struct hb_is_inplace_context_t
-{
-  inline const char *get_name (void) { return "IS_INPLACE"; }
-  static const unsigned int max_debug_depth = HB_DEBUG_IS_INPLACE;
-  typedef bool return_t;
-  typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned int lookup_index);
-  template <typename T>
-  inline return_t dispatch (const T &obj) { return obj.is_inplace (this); }
-  static return_t default_return_value (void) { return true; }
-  bool stop_sublookup_iteration (return_t r) const { return !r; }
-
-  return_t recurse (unsigned int lookup_index)
-  {
-    if (unlikely (nesting_level_left == 0 || !recurse_func))
-      return default_return_value ();
-
-    nesting_level_left--;
-    bool ret = recurse_func (this, lookup_index);
-    nesting_level_left++;
-    return ret;
-  }
-
-  hb_face_t *face;
-  recurse_func_t recurse_func;
-  unsigned int nesting_level_left;
-  unsigned int debug_depth;
-
-  hb_is_inplace_context_t (hb_face_t *face_,
-			   unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
-			   face (face_),
-			   recurse_func (NULL),
-			   nesting_level_left (nesting_level_left_),
-			   debug_depth (0) {}
-
-  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
-};
-
-
-
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
 #define TRACE_CLOSURE(this) \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
@@ -396,25 +346,25 @@ struct hb_apply_context_t
     };
 
     inline may_skip_t
     may_skip (const hb_apply_context_t *c,
 	      const hb_glyph_info_t    &info) const
     {
       unsigned int property;
 
-      property = info.glyph_props();
+      property = _hb_glyph_info_get_glyph_props (&info);
 
       if (!c->match_properties (info.codepoint, property, lookup_props))
 	return SKIP_YES;
 
       if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
-		    !is_a_ligature (info)))
+		    !_hb_glyph_info_ligated (&info)))
 	return SKIP_MAYBE;
 
       return SKIP_NO;
     }
 
     protected:
     unsigned int lookup_props;
     bool ignore_zwnj;
@@ -605,46 +555,57 @@ struct hb_apply_context_t
   }
 
   inline bool
   check_glyph_property (hb_glyph_info_t *info,
 			unsigned int  lookup_props) const
   {
     unsigned int property;
 
-    property = info->glyph_props();
+    property = _hb_glyph_info_get_glyph_props (info);
 
     return match_properties (info->codepoint, property, lookup_props);
   }
 
-  inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
+  inline void _set_glyph_props (hb_codepoint_t glyph_index,
+			  unsigned int class_guess = 0,
+			  bool ligature = false) const
   {
+    unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
+			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+    add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+    if (ligature)
+      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
     if (likely (has_glyph_classes))
-      buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index);
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
     else if (class_guess)
-      buffer->cur().glyph_props() = class_guess;
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
   }
 
-  inline void output_glyph (hb_codepoint_t glyph_index,
-			    unsigned int class_guess = 0) const
+  inline void replace_glyph (hb_codepoint_t glyph_index) const
   {
-    set_class (glyph_index, class_guess);
-    buffer->output_glyph (glyph_index);
-  }
-  inline void replace_glyph (hb_codepoint_t glyph_index,
-			     unsigned int class_guess = 0) const
-  {
-    set_class (glyph_index, class_guess);
+    _set_glyph_props (glyph_index);
     buffer->replace_glyph (glyph_index);
   }
-  inline void replace_glyph_inplace (hb_codepoint_t glyph_index,
-				     unsigned int class_guess = 0) const
+  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+  {
+    _set_glyph_props (glyph_index);
+    buffer->cur().codepoint = glyph_index;
+  }
+  inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
+					   unsigned int class_guess) const
   {
-    set_class (glyph_index, class_guess);
-    buffer->cur().codepoint = glyph_index;
+    _set_glyph_props (glyph_index, class_guess, true);
+    buffer->replace_glyph (glyph_index);
+  }
+  inline void output_glyph (hb_codepoint_t glyph_index,
+			    unsigned int class_guess) const
+  {
+    _set_glyph_props (glyph_index, class_guess);
+    buffer->output_glyph (glyph_index);
   }
 };
 
 
 
 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
@@ -747,23 +708,28 @@ static inline bool would_match_input (hb
 
   return true;
 }
 static inline bool match_input (hb_apply_context_t *c,
 				unsigned int count, /* Including the first glyph (not matched) */
 				const USHORT input[], /* Array of input values--start with second glyph */
 				match_func_t match_func,
 				const void *match_data,
-				unsigned int *end_offset = NULL,
+				unsigned int *end_offset,
+				unsigned int match_positions[MAX_CONTEXT_LENGTH],
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
   TRACE_APPLY (NULL);
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
+  if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
   skippy_iter.set_match_func (match_func, match_data, input);
   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
   /*
    * This is perhaps the trickiest part of OpenType...  Remarks:
    *
    * - If all components of the ligature were marks, we call this a mark ligature.
    *
@@ -775,72 +741,75 @@ static inline bool match_input (hb_apply
    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
    *   There is an exception to this: If a ligature tries ligating with marks that
    *   belong to it itself, go ahead, assuming that the font designer knows what
    *   they are doing (otherwise it can break Indic stuff when a matra wants to
    *   ligate with a conjunct...)
    */
 
-  bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
 
   unsigned int total_component_count = 0;
-  total_component_count += get_lig_num_comps (c->buffer->cur());
+  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
 
-  unsigned int first_lig_id = get_lig_id (c->buffer->cur());
-  unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
+  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
 
+  match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
     if (!skippy_iter.next ()) 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]);
+    match_positions[i] = skippy_iter.idx;
+
+    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
+    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&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. */
       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
 	return TRACE_RETURN (false);
     } else {
       /* If first component was NOT attached to a previous ligature component,
        * all subsequent components should also NOT be attached to any ligature
        * component, unless they are attached to the first component itself! */
       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
 	return TRACE_RETURN (false);
     }
 
-    is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
-    total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
+    is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
+    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
   }
 
-  if (end_offset)
-    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
+  *end_offset = skippy_iter.idx - 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 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 */
-				 match_func_t match_func,
-				 const void *match_data,
+				 unsigned int count, /* Including the first glyph */
+				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+				 unsigned int match_length,
 				 hb_codepoint_t lig_glyph,
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
-  skippy_iter.set_match_func (match_func, match_data, input);
-  if (skippy_iter.has_no_chance ()) return;
+  TRACE_APPLY (NULL);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
 
   /*
    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
    *   the ligature to keep its old ligature id.  This will allow it to attach to
    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
    *   later, we don't want them to lose their ligature id/component, otherwise
@@ -861,58 +830,59 @@ static inline void ligate_input (hb_appl
    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
    *   the new ligature with a component value of 2.
    *
    *   This in fact happened to a font...  See:
    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
    */
 
   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
-  unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
-  unsigned int last_lig_id = get_lig_id (c->buffer->cur());
-  unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
+  unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
+  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   unsigned int components_so_far = last_num_components;
 
   if (!is_mark_ligature)
   {
-    set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
-    if (_hb_glyph_info_get_general_category (&c->buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
-      _hb_glyph_info_set_general_category (&c->buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
+    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+      _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
+    }
   }
-  c->replace_glyph (lig_glyph, klass);
+  c->replace_glyph_with_ligature (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
-    if (!skippy_iter.next ()) return;
-
-    while (c->buffer->idx < skippy_iter.idx)
+    while (buffer->idx < match_positions[i])
     {
       if (!is_mark_ligature) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
-	set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
+				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
+	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
       }
-      c->buffer->next_glyph ();
+      buffer->next_glyph ();
     }
 
-    last_lig_id = get_lig_id (c->buffer->cur());
-    last_num_components = get_lig_num_comps (c->buffer->cur());
+    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
     components_so_far += last_num_components;
 
     /* Skip the base glyph */
-    c->buffer->idx++;
+    buffer->idx++;
   }
 
   if (!is_mark_ligature && last_lig_id) {
     /* Re-adjust components for any marks following. */
-    for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
-      if (last_lig_id == get_lig_id (c->buffer->info[i])) {
+    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
 	unsigned int new_lig_comp = components_so_far - last_num_components +
-				    MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
-	set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
+				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
+	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
       } else
 	break;
     }
   }
 }
 
 static inline bool match_backtrack (hb_apply_context_t *c,
 				    unsigned int count,
@@ -977,109 +947,92 @@ static inline void recurse_lookups (cont
 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
     c->recurse (lookupRecord[i].lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
-				 const USHORT input[], /* Array of input values--start with second glyph */
-				 match_func_t match_func,
-				 const void *match_data,
+				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
 				 unsigned int lookupCount,
-				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
+				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
+				 unsigned int match_length)
 {
   TRACE_APPLY (NULL);
 
-  unsigned int end = c->buffer->len;
-  if (unlikely (count == 0 || c->buffer->idx + count > end))
-    return TRACE_RETURN (false);
+  hb_buffer_t *buffer = c->buffer;
+  unsigned int end;
 
-  /* TODO We don't support lookupRecord arrays that are not increasing:
-   *      Should be easy for in_place ones at least. */
+  /* All positions are distance from beginning of *output* buffer.
+   * Adjust. */
+  {
+    unsigned int bl = buffer->backtrack_len ();
+    end = bl + match_length;
 
-  /* 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.
-   */
+    int delta = bl - buffer->idx;
+    /* Convert positions to new indexing. */
+    for (unsigned int j = 0; j < count; j++)
+      match_positions[j] += delta;
+  }
 
-  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
-  skippy_iter.set_match_func (match_func, match_data, input);
-  uint8_t syllable = c->buffer->cur().syllable();
+  for (unsigned int i = 0; i < lookupCount; i++)
+  {
+    unsigned int idx = lookupRecord[i].sequenceIndex;
+    if (idx >= count)
+      continue;
 
-  unsigned int i = 0;
-  if (lookupCount && 0 == lookupRecord->sequenceIndex)
-  {
-    unsigned int old_pos = c->buffer->idx;
+    buffer->move_to (match_positions[idx]);
 
-    /* Apply a lookup */
-    bool done = c->recurse (lookupRecord->lookupListIndex);
+    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    if (!c->recurse (lookupRecord[i].lookupListIndex))
+      continue;
+
+    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    int delta = new_len - orig_len;
 
-    lookupRecord++;
-    lookupCount--;
-    i++;
+    if (!delta)
+        continue;
+
+    /* Recursed lookup changed buffer len.  Adjust. */
 
-    if (!done)
-      goto not_applied;
-    else
+    /* end can't go back past the current match position. */
+    end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
+
+    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
+
+    if (delta > 0)
     {
-      if (c->table_index == 1)
-        c->buffer->idx = old_pos + 1;
-      /* Reinitialize iterator. */
-      hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
-      tmp.set_syllable (syllable);
-      skippy_iter = tmp;
-    }
-  }
-  else
-  {
-  not_applied:
-    /* No lookup applied for this index */
-    c->buffer->next_glyph ();
-    i++;
-  }
-  while (i < count)
-  {
-    if (!skippy_iter.next ()) return TRACE_RETURN (true);
-    while (c->buffer->idx < skippy_iter.idx)
-      c->buffer->next_glyph ();
-
-    if (lookupCount && i == lookupRecord->sequenceIndex)
-    {
-      unsigned int old_pos = c->buffer->idx;
-
-      /* Apply a lookup */
-      bool done = c->recurse (lookupRecord->lookupListIndex);
-
-      lookupRecord++;
-      lookupCount--;
-      i++;
-
-      if (!done)
-	goto not_applied2;
-      else
-      {
-	if (c->table_index == 1)
-	  c->buffer->idx = old_pos + 1;
-        /* Reinitialize iterator. */
-	hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
-	tmp.set_syllable (syllable);
-	skippy_iter = tmp;
-      }
+      if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
+	break;
     }
     else
     {
-    not_applied2:
-      /* No lookup applied for this index */
-      c->buffer->next_glyph ();
-      i++;
+      /* NOTE: delta is negative. */
+      delta = MAX (delta, (int) next - (int) count);
+      next -= delta;
     }
+
+    /* Shift! */
+    memmove (match_positions + next + delta, match_positions + next,
+	     (count - next) * sizeof (match_positions[0]));
+    next += delta;
+    count += delta;
+
+    /* Fill in new entries. */
+    for (unsigned int j = idx + 1; j < next; j++)
+      match_positions[j] = match_positions[j - 1] + 1;
+
+    /* And fixup the rest. */
+    for (; next < count; next++)
+      match_positions[next] += delta;
   }
 
+  buffer->move_to (end);
+
   return TRACE_RETURN (true);
 }
 
 
 
 /* Contextual lookups */
 
 struct ContextClosureLookupContext
@@ -1141,38 +1094,30 @@ static inline bool context_would_apply_l
 }
 static inline bool context_apply_lookup (hb_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
 					 const USHORT input[], /* Array of input values--start with second glyph */
 					 unsigned int lookupCount,
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
 {
+  unsigned int match_length = 0;
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
-		      lookup_context.funcs.match, lookup_context.match_data)
+		      lookup_context.funcs.match, lookup_context.match_data,
+		      &match_length, match_positions)
       && apply_lookup (c,
-		       inputCount, input,
-		       lookup_context.funcs.match, lookup_context.match_data,
-		       lookupCount, lookupRecord);
+		       inputCount, match_positions,
+		       lookupCount, lookupRecord,
+		       match_length);
 }
 
 struct Rule
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
-    unsigned int count = lookupCount;
-    for (unsigned int i = 0; i < count; i++)
-      if (!c->recurse (lookupRecord[i].lookupListIndex))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     context_closure_lookup (c,
 			    inputCount, input,
 			    lookupCount, lookupRecord,
 			    lookup_context);
@@ -1222,26 +1167,16 @@ struct Rule
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
 };
 
 struct RuleSet
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if (!(this+rule[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
@@ -1288,26 +1223,16 @@ struct RuleSet
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 
 struct ContextFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+ruleSet[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
@@ -1384,26 +1309,16 @@ struct ContextFormat1
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 
 struct ContextFormat2
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+ruleSet[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &class_def = this+classDef;
 
@@ -1489,27 +1404,16 @@ struct ContextFormat2
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (8, ruleSet);
 };
 
 
 struct ContextFormat3
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
-    unsigned int count = lookupCount;
-    for (unsigned int i = 0; i < count; i++)
-      if (!c->recurse (lookupRecord[i].lookupListIndex))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage[0]).intersects (c->glyphs))
       return;
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
@@ -1721,49 +1625,37 @@ static inline bool chain_context_apply_l
 					       unsigned int inputCount, /* Including the first glyph (not matched) */
 					       const USHORT input[], /* Array of input values--start with second glyph */
 					       unsigned int lookaheadCount,
 					       const USHORT lookahead[],
 					       unsigned int lookupCount,
 					       const LookupRecord lookupRecord[],
 					       ChainContextApplyLookupContext &lookup_context)
 {
-  unsigned int lookahead_offset = 0;
+  unsigned int match_length = 0;
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data[1],
-		      &lookahead_offset)
+		      &match_length, match_positions)
       && match_backtrack (c,
 			  backtrackCount, backtrack,
 			  lookup_context.funcs.match, lookup_context.match_data[0])
       && match_lookahead (c,
 			  lookaheadCount, lookahead,
 			  lookup_context.funcs.match, lookup_context.match_data[2],
-			  lookahead_offset)
+			  match_length)
       && apply_lookup (c,
-		       inputCount, input,
-		       lookup_context.funcs.match, lookup_context.match_data[1],
-		       lookupCount, lookupRecord);
+		       inputCount, match_positions,
+		       lookupCount, lookupRecord,
+		       match_length);
 }
 
 struct ChainRule
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
-    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-    unsigned int count = lookup.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!c->recurse (lookup.array[i].lookupListIndex))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.array,
@@ -1839,26 +1731,16 @@ struct ChainRule
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
   DEFINE_SIZE_MIN (8);
 };
 
 struct ChainRuleSet
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int num_rules = rule.len;
-    for (unsigned int i = 0; i < num_rules; i++)
-      if (!(this+rule[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
@@ -1902,26 +1784,16 @@ struct ChainRuleSet
 		rule;			/* Array of ChainRule tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 struct ChainContextFormat1
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+ruleSet[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       {NULL, NULL, NULL}
@@ -1995,26 +1867,16 @@ struct ChainContextFormat1
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 struct ChainContextFormat2
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!(this+ruleSet[i]).is_inplace (c))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
@@ -2129,30 +1991,16 @@ struct ChainContextFormat2
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (12, ruleSet);
 };
 
 struct ChainContextFormat3
 {
-  inline bool is_inplace (hb_is_inplace_context_t *c) const
-  {
-    TRACE_IS_INPLACE (this);
-    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
-    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
-
-    unsigned int count = lookup.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (!c->recurse (lookup.array[i].lookupListIndex))
-        return TRACE_RETURN (false);
-    return TRACE_RETURN (true);
-  }
-
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2007,2008,2009  Red Hat, Inc.
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2012,2013  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.
@@ -33,173 +33,40 @@
 
 #include "hb-ot-layout.h"
 
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
 #include "hb-set-private.hh"
 
 
-/* buffer var allocations, used during the GSUB/GPOS processing */
-#define glyph_props()		var1.u16[0] /* GDEF glyph properties */
-#define syllable()		var1.u8[2] /* GSUB/GPOS shaping boundaries */
-#define lig_props()		var1.u8[3] /* GSUB/GPOS ligature tracking */
-
-/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0()	var2.u8[0]
-#define unicode_props1()	var2.u8[1]
-
-
-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_default_ignorable (info->codepoint) ? 0x80 : 0) |
-			   (info->codepoint == 0x200C ? 0x40 : 0) |
-			   (info->codepoint == 0x200D ? 0x20 : 0);
-  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
-}
-
-inline void
-_hb_glyph_info_set_general_category (hb_glyph_info_t *info, hb_unicode_general_category_t gen_cat)
-{
-  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~0x1F);
-}
-
-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() & 0x1F);
-}
-
-inline void
-_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
-{
-  info->unicode_props1() = modified_class;
-}
-
-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_default_ignorable (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x80);
-}
-
-inline hb_bool_t
-_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x40);
-}
-
-inline hb_bool_t
-_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x20);
-}
-
-
-#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
-
 /*
  * GDEF
  */
 
-typedef enum {
-  HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED	= 1 << HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED,
-  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 1 << HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH,
-  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE	= 1 << HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE,
-  HB_OT_LAYOUT_GLYPH_PROPS_MARK		= 1 << HB_OT_LAYOUT_GLYPH_CLASS_MARK,
-  HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT	= 1 << HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT
+typedef enum
+{
+  /* The following three match LookupFlags::Ignore* numbers. */
+  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 0x02u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE	= 0x04u,
+  HB_OT_LAYOUT_GLYPH_PROPS_MARK		= 0x08u,
+
+  /* The following are used internally; not derived from GDEF. */
+  HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED	= 0x10u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED	= 0x20u,
+
+  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+					  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED
 } hb_ot_layout_glyph_class_mask_t;
 
 
-
 /*
  * GSUB/GPOS
  */
 
-/* lig_id / lig_comp
- *
- * When a ligature is formed:
- *
- *   - The ligature glyph and any marks in between all the same newly allocated
- *     lig_id,
- *   - The ligature glyph will get lig_num_comps set to the number of components
- *   - The marks get lig_comp > 0, reflecting which component of the ligature
- *     they were applied to.
- *   - This is used in GPOS to attach marks to the right component of a ligature
- *     in MarkLigPos.
- *
- * When a multiple-substitution is done:
- *
- *   - All resulting glyphs will have lig_id = 0,
- *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
- *   - This is used in GPOS to attach marks to the first component of a
- *     multiple substitution in MarkBasePos.
- *
- * The numbers are also used in GPOS to do mark-to-mark positioning only
- * to marks that belong to the same component of a ligature in MarkMarPos.
- */
-#define IS_LIG_BASE 0x10
-static inline void
-set_lig_props_for_ligature (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_num_comps)
-{
-  info.lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
-}
-static inline void
-set_lig_props_for_mark (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
-{
-  info.lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
-}
-static inline void
-set_lig_props_for_component (hb_glyph_info_t &info, unsigned int comp)
-{
-  set_lig_props_for_mark (info, 0, comp);
-}
-
-static inline unsigned int
-get_lig_id (const hb_glyph_info_t &info)
-{
-  return info.lig_props() >> 5;
-}
-static inline bool
-is_a_ligature (const hb_glyph_info_t &info)
-{
-  return !!(info.lig_props() & IS_LIG_BASE);
-}
-static inline unsigned int
-get_lig_comp (const hb_glyph_info_t &info)
-{
-  if (is_a_ligature (info))
-    return 0;
-  else
-    return info.lig_props() & 0x0F;
-}
-static inline unsigned int
-get_lig_num_comps (const hb_glyph_info_t &info)
-{
-  if ((info.glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) && is_a_ligature (info))
-    return info.lig_props() & 0x0F;
-  else
-    return 1;
-}
-
-static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
-  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_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);
 
 
@@ -287,10 +154,272 @@ struct hb_ot_layout_t
 
 HB_INTERNAL hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face);
 
 HB_INTERNAL void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 
 
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
+
+
+/*
+ * Buffer var routines.
+ */
+
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props0()	var2.u8[0]
+#define unicode_props1()	var2.u8[1]
+
+/* buffer var allocations, used during the GSUB/GPOS processing */
+#define glyph_props()		var1.u16[0] /* GDEF glyph properties */
+#define lig_props()		var1.u8[2] /* GSUB/GPOS ligature tracking */
+#define syllable()		var1.u8[3] /* GSUB/GPOS shaping boundaries */
+
+/* unicode_props */
+
+enum {
+  MASK0_ZWJ       = 0x20u,
+  MASK0_ZWNJ      = 0x40u,
+  MASK0_IGNORABLE = 0x80u,
+  MASK0_GEN_CAT   = 0x1Fu
+};
+
+inline void
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
+  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+			   (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
+			   (info->codepoint == 0x200C ? MASK0_ZWNJ : 0) |
+			   (info->codepoint == 0x200D ? MASK0_ZWJ : 0);
+  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+}
+
+inline void
+_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
+				     hb_unicode_general_category_t gen_cat)
+{
+  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
+}
+
+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() & MASK0_GEN_CAT);
+}
+
+inline void
+_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
+					     unsigned int modified_class)
+{
+  info->unicode_props1() = modified_class;
+}
+
+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_default_ignorable (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_IGNORABLE);
+}
+
+inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_ZWNJ);
+}
+
+inline hb_bool_t
+_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_ZWJ);
+}
+
+inline void
+_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
+{
+  info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
+}
+
+/* lig_props: aka lig_id / lig_comp
+ *
+ * When a ligature is formed:
+ *
+ *   - The ligature glyph and any marks in between all the same newly allocated
+ *     lig_id,
+ *   - The ligature glyph will get lig_num_comps set to the number of components
+ *   - The marks get lig_comp > 0, reflecting which component of the ligature
+ *     they were applied to.
+ *   - This is used in GPOS to attach marks to the right component of a ligature
+ *     in MarkLigPos,
+ *   - Note that when marks are ligated together, much of the above is skipped
+ *     and the current lig_id reused.
+ *
+ * When a multiple-substitution is done:
+ *
+ *   - All resulting glyphs will have lig_id = 0,
+ *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
+ *   - This is used in GPOS to attach marks to the first component of a
+ *     multiple substitution in MarkBasePos.
+ *
+ * The numbers are also used in GPOS to do mark-to-mark positioning only
+ * to marks that belong to the same component of the same ligature.
+ */
+
+static inline void
+_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
+{
+  info->lig_props() = 0;
+}
+
+#define IS_LIG_BASE 0x10
+
+static inline void
+_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
+					   unsigned int lig_id,
+					   unsigned int lig_num_comps)
+{
+  info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
+				       unsigned int lig_id,
+				       unsigned int lig_comp)
+{
+  info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
+{
+  _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
+{
+  return info->lig_props() >> 5;
+}
+
+static inline bool
+_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
+{
+  return !!(info->lig_props() & IS_LIG_BASE);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
+{
+  if (_hb_glyph_info_ligated_internal (info))
+    return 0;
+  else
+    return info->lig_props() & 0x0F;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
+{
+  if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
+      _hb_glyph_info_ligated_internal (info))
+    return info->lig_props() & 0x0F;
+  else
+    return 1;
+}
+
+static inline uint8_t
+_hb_allocate_lig_id (hb_buffer_t *buffer) {
+  uint8_t lig_id = buffer->next_serial () & 0x07;
+  if (unlikely (!lig_id))
+    lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
+  return lig_id;
+}
+
+/* glyph_props: */
+
+inline void
+_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
+{
+  info->glyph_props() = props;
+}
+
+inline unsigned int
+_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
+{
+  return info->glyph_props();
+}
+
+inline bool
+_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+}
+
+inline bool
+_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+}
+
+inline bool
+_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+}
+
+static inline bool
+_hb_glyph_info_substituted (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
+static inline bool
+_hb_glyph_info_ligated (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+}
+
+/* Allocation / deallocation. */
+
+inline void
+_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
+}
+
+inline void
+_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
+}
+
+inline void
+_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
+  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
+  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+}
+
+inline void
+_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
+}
+
+/* Make sure no one directly touches our props... */
+#undef unicode_props0
+#undef unicode_props1
+#undef lig_props
+#undef glyph_props
+
 
 #endif /* HB_OT_LAYOUT_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -409,16 +409,34 @@ hb_ot_layout_feature_get_lookups (hb_fac
 				  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);
 }
 
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+				     hb_tag_t      table_tag)
+{
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      return hb_ot_layout_from_face (face)->gsub_lookup_count;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      return hb_ot_layout_from_face (face)->gpos_lookup_count;
+    }
+  }
+  return 0;
+}
+
 static void
 _hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
 				       hb_tag_t        table_tag,
 				       unsigned int    feature_index,
 				       hb_set_t       *lookup_indexes /* OUT */)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
@@ -760,29 +778,31 @@ hb_ot_layout_get_size_params (hb_face_t 
  * Parts of different types are implemented here such that they have direct
  * access to GSUB/GPOS lookups.
  */
 
 
 struct GSUBProxy
 {
   static const unsigned int table_index = 0;
+  static const bool inplace = false;
   typedef OT::SubstLookup Lookup;
 
   GSUBProxy (hb_face_t *face) :
     table (*hb_ot_layout_from_face (face)->gsub),
     accels (hb_ot_layout_from_face (face)->gsub_accels) {}
 
   const OT::GSUB &table;
   const hb_ot_layout_lookup_accelerator_t *accels;
 };
 
 struct GPOSProxy
 {
   static const unsigned int table_index = 1;
+  static const bool inplace = true;
   typedef OT::PosLookup Lookup;
 
   GPOSProxy (hb_face_t *face) :
     table (*hb_ot_layout_from_face (face)->gpos),
     accels (hb_ot_layout_from_face (face)->gpos_accels) {}
 
   const OT::GPOS &table;
   const hb_ot_layout_lookup_accelerator_t *accels;
@@ -800,65 +820,64 @@ static inline bool apply_once (OT::hb_ap
 
 template <typename Proxy>
 static inline bool
 apply_string (OT::hb_apply_context_t *c,
 	      const typename Proxy::Lookup &lookup,
 	      const hb_ot_layout_lookup_accelerator_t &accel)
 {
   bool ret = false;
-  OT::hb_is_inplace_context_t inplace_c (c->face);
-  bool inplace = lookup.is_inplace (&inplace_c);
+  hb_buffer_t *buffer = c->buffer;
 
-  if (unlikely (!c->buffer->len || !c->lookup_mask))
+  if (unlikely (!buffer->len || !c->lookup_mask))
     return false;
 
   c->set_lookup (lookup);
 
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
     if (Proxy::table_index == 0)
-      c->buffer->clear_output ();
-    c->buffer->idx = 0;
+      buffer->clear_output ();
+    buffer->idx = 0;
 
-    while (c->buffer->idx < c->buffer->len)
+    while (buffer->idx < buffer->len)
     {
-      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
-	  (c->buffer->cur().mask & c->lookup_mask) &&
+      if (accel.digest.may_have (buffer->cur().codepoint) &&
+	  (buffer->cur().mask & c->lookup_mask) &&
 	  apply_once (c, lookup))
 	ret = true;
       else
-	c->buffer->next_glyph ();
+	buffer->next_glyph ();
     }
     if (ret)
     {
-      if (!inplace)
-	c->buffer->swap_buffers ();
+      if (!Proxy::inplace)
+	buffer->swap_buffers ();
       else
-        assert (!c->buffer->has_separate_output ());
+        assert (!buffer->has_separate_output ());
     }
   }
   else
   {
     /* in-place backward substitution/positioning */
     if (Proxy::table_index == 0)
-      c->buffer->remove_output ();
-    c->buffer->idx = c->buffer->len - 1;
+      buffer->remove_output ();
+    buffer->idx = buffer->len - 1;
     do
     {
-      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
-	  (c->buffer->cur().mask & c->lookup_mask) &&
+      if (accel.digest.may_have (buffer->cur().codepoint) &&
+	  (buffer->cur().mask & c->lookup_mask) &&
 	  apply_once (c, lookup))
 	ret = true;
-      else
-	c->buffer->idx--;
+      /* The reverse lookup doesn't "advance" cursor (for good reason). */
+      buffer->idx--;
 
     }
-    while ((int) c->buffer->idx >= 0);
+    while ((int) buffer->idx >= 0);
   }
 
   return ret;
 }
 
 template <typename Proxy>
 inline void hb_ot_map_t::apply (const Proxy &proxy,
 				const hb_ot_shape_plan_t *plan,
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -175,16 +175,21 @@ hb_ot_layout_language_find_feature (hb_f
 unsigned int
 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 */);
 
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+				     hb_tag_t      table_tag);
+
+
 void
 hb_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 */);
 
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -35,27 +35,33 @@ void
 hb_ot_map_t::add_lookups (hb_face_t    *face,
 			  unsigned int  table_index,
 			  unsigned int  feature_index,
 			  hb_mask_t     mask,
 			  bool          auto_zwj)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
+  unsigned int table_lookup_count;
+
+  table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
 
   offset = 0;
   do {
     len = ARRAY_LENGTH (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++) {
+    for (unsigned int i = 0; i < len; i++)
+    {
+      if (lookup_indices[i] >= table_lookup_count)
+	continue;
       hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
       if (unlikely (!lookup))
         return;
       lookup->mask = mask;
       lookup->index = lookup_indices[i];
       lookup->auto_zwj = auto_zwj;
     }
 
@@ -170,17 +176,17 @@ hb_ot_map_builder_t::compile (hb_ot_map_
       bits_needed = 0;
     else
       bits_needed = _hb_bit_storage (info->max_value);
 
     if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
       continue; /* Feature disabled, or not enough bits. */
 
 
-    bool found = false;
+    hb_bool_t found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
       found |= hb_ot_layout_language_find_feature (face,
 						   table_tags[table_index],
 						   script_index[table_index],
 						   language_index[table_index],
 						   info->tag,
 						   &feature_index[table_index]);
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -152,16 +152,21 @@ static const struct arabic_state_table_e
   { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
 
   /* State 6: prev was DALATH/RISH, not willing to join. */
   { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
 };
 
 
 static void
+nuke_joiners (const hb_ot_shape_plan_t *plan,
+	      hb_font_t *font,
+	      hb_buffer_t *buffer);
+
+static void
 arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
 		       hb_font_t *font,
 		       hb_buffer_t *buffer);
 
 static void
 collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
   hb_ot_map_builder_t *map = &plan->map;
@@ -171,16 +176,18 @@ collect_features_arabic (hb_ot_shape_pla
    * ligature work correctly. It's unfortunate though...
    *
    * This also makes Arial Bold in Windows7 work.  See:
    * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
    *
    * TODO: Add test cases for these two.
    */
 
+  map->add_gsub_pause (nuke_joiners);
+
   map->add_global_bool_feature (HB_TAG('c','c','m','p'));
   map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
   map->add_gsub_pause (NULL);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
     map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */
 
@@ -268,17 +275,18 @@ arabic_joining (hb_buffer_t *buffer)
     if (unlikely (this_type == JOINING_TYPE_T)) {
       buffer->info[i].arabic_shaping_action() = NONE;
       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;
+      for (; prev < i; prev++)
+	buffer->info[prev].arabic_shaping_action() = entry->prev_action;
 
     buffer->info[i].arabic_shaping_action() = entry->curr_action;
 
     prev = i;
     state = entry->next_state;
   }
 
   if (!(buffer->flags & HB_BUFFER_FLAG_EOT))
@@ -309,16 +317,27 @@ setup_masks_arabic (const hb_ot_shape_pl
   arabic_joining (buffer);
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
     buffer->info[i].mask |= arabic_plan->mask_array[buffer->info[i].arabic_shaping_action()];
 }
 
 
 static void
+nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
+	      hb_font_t *font HB_UNUSED,
+	      hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_zwj (&buffer->info[i]))
+      _hb_glyph_info_flip_joiners (&buffer->info[i]);
+}
+
+static void
 arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
 		       hb_font_t *font,
 		       hb_buffer_t *buffer)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   if (!arabic_plan->do_fallback)
     return;
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -50,58 +50,62 @@ static const unsigned char _indic_syllab
 	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, 4u, 14u, 
 	4u, 14u, 5u, 7u, 5u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 
 	7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 1u, 16u, 13u, 13u, 4u, 4u, 6u, 6u, 
 	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
-	6u, 6u, 16u, 16u, 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, 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, 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, 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, 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, 17u, 1u, 16u, 4u, 14u, 1u, 16u, 
-	3u, 17u, 3u, 14u, 4u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 14u, 3u, 14u, 
-	1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 
-	4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 8u, 14u, 3u, 17u, 3u, 9u, 8u, 9u, 
-	3u, 9u, 3u, 13u, 1u, 16u, 0
+	6u, 6u, 16u, 16u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 18u, 8u, 18u, 
+	5u, 10u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 18u, 3u, 18u, 8u, 18u, 
+	3u, 10u, 8u, 10u, 3u, 18u, 3u, 18u, 3u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 
+	3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 
+	6u, 18u, 3u, 18u, 1u, 18u, 4u, 31u, 4u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 3u, 31u, 3u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 18u, 8u, 18u, 
+	5u, 10u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 18u, 3u, 18u, 8u, 18u, 
+	3u, 10u, 8u, 10u, 3u, 18u, 3u, 18u, 3u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 
+	3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 
+	6u, 18u, 3u, 18u, 1u, 18u, 4u, 31u, 4u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	4u, 14u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 
+	4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 
+	4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 18u, 8u, 18u, 5u, 10u, 
+	9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 18u, 3u, 18u, 8u, 18u, 3u, 10u, 
+	8u, 10u, 3u, 18u, 3u, 18u, 3u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 
+	4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 6u, 18u, 
+	3u, 18u, 1u, 18u, 4u, 31u, 4u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	4u, 14u, 3u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 1u, 18u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 18u, 8u, 18u, 
+	5u, 10u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 18u, 3u, 18u, 8u, 18u, 
+	3u, 10u, 8u, 10u, 3u, 18u, 3u, 18u, 3u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 
+	3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 
+	6u, 18u, 3u, 18u, 1u, 18u, 4u, 31u, 4u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 1u, 18u, 3u, 31u, 3u, 31u, 1u, 18u, 1u, 18u, 1u, 18u, 1u, 18u, 
+	1u, 18u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 18u, 1u, 18u, 3u, 31u, 
+	3u, 31u, 4u, 31u, 5u, 10u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 10u, 
+	8u, 10u, 3u, 31u, 3u, 31u, 1u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 
+	4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 5u, 18u, 3u, 18u, 4u, 18u, 8u, 18u, 
+	3u, 18u, 3u, 18u, 8u, 18u, 3u, 18u, 3u, 18u, 1u, 18u, 3u, 10u, 8u, 10u, 
+	5u, 10u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 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, 
@@ -116,58 +120,62 @@ static const char _indic_syllable_machin
 	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, 11, 
 	11, 3, 3, 3, 3, 1, 3, 3, 
 	1, 3, 3, 1, 16, 1, 1, 1, 
 	1, 4, 1, 1, 4, 1, 1, 4, 
-	1, 1, 16, 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, 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, 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, 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, 15, 16, 11, 16, 
-	15, 12, 11, 5, 1, 1, 12, 12, 
-	16, 12, 11, 10, 12, 11, 10, 12, 
-	11, 10, 12, 11, 7, 15, 7, 2, 
-	7, 11, 16
+	1, 1, 31, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 14, 11, 
+	6, 2, 2, 1, 6, 16, 16, 11, 
+	8, 3, 16, 16, 16, 16, 15, 14, 
+	16, 15, 14, 16, 15, 14, 16, 15, 
+	13, 16, 18, 28, 15, 29, 29, 18, 
+	18, 18, 18, 18, 29, 29, 18, 18, 
+	18, 18, 18, 29, 29, 18, 18, 18, 
+	18, 18, 29, 29, 18, 18, 18, 18, 
+	18, 29, 29, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 14, 11, 
+	6, 2, 2, 1, 6, 16, 16, 11, 
+	8, 3, 16, 16, 16, 16, 15, 14, 
+	16, 15, 14, 16, 15, 14, 16, 15, 
+	13, 16, 18, 28, 15, 29, 29, 18, 
+	18, 18, 18, 18, 29, 29, 18, 18, 
+	18, 18, 18, 29, 29, 18, 18, 18, 
+	18, 18, 29, 29, 18, 18, 18, 18, 
+	11, 18, 29, 29, 28, 18, 29, 29, 
+	28, 18, 29, 29, 28, 18, 29, 29, 
+	28, 18, 29, 29, 28, 14, 11, 6, 
+	2, 2, 1, 6, 16, 16, 11, 8, 
+	3, 16, 16, 16, 16, 15, 14, 16, 
+	15, 14, 16, 15, 14, 16, 15, 13, 
+	16, 18, 28, 15, 29, 29, 18, 18, 
+	18, 18, 18, 29, 29, 18, 18, 18, 
+	18, 18, 29, 29, 18, 18, 18, 18, 
+	18, 29, 29, 18, 18, 18, 18, 18, 
+	11, 29, 11, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 18, 29, 
+	29, 28, 18, 29, 29, 28, 14, 11, 
+	6, 2, 2, 1, 6, 16, 16, 11, 
+	8, 3, 16, 16, 16, 16, 15, 14, 
+	16, 15, 14, 16, 15, 14, 16, 15, 
+	13, 16, 18, 28, 15, 29, 29, 18, 
+	18, 18, 18, 18, 29, 29, 18, 18, 
+	18, 18, 18, 29, 29, 18, 18, 18, 
+	18, 18, 29, 29, 18, 18, 18, 18, 
+	18, 29, 31, 29, 31, 15, 18, 29, 
+	29, 28, 6, 2, 2, 1, 6, 8, 
+	3, 29, 29, 18, 16, 15, 14, 16, 
+	15, 14, 16, 15, 14, 16, 15, 11, 
+	16, 16, 11, 16, 16, 18, 8, 3, 
+	6, 2, 2, 1, 6
 };
 
 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, 
@@ -182,58 +190,62 @@ static const short _indic_syllable_machi
 	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, 
 	848, 860, 864, 868, 872, 876, 878, 882, 
 	886, 888, 892, 896, 898, 915, 917, 919, 
 	921, 923, 928, 930, 932, 937, 939, 941, 
-	946, 948, 950, 967, 983, 996, 1008, 1025, 
-	1041, 1054, 1066, 1083, 1099, 1112, 1124, 1141, 
-	1157, 1170, 1182, 1199, 1215, 1228, 1240, 1251, 
-	1259, 1265, 1267, 1269, 1285, 1293, 1296, 1304, 
-	1316, 1329, 1342, 1354, 1365, 1378, 1390, 1401, 
-	1414, 1426, 1437, 1450, 1462, 1472, 1485, 1497, 
-	1514, 1527, 1540, 1557, 1574, 1591, 1608, 1625, 
-	1638, 1651, 1668, 1685, 1702, 1719, 1736, 1749, 
-	1762, 1779, 1796, 1813, 1830, 1847, 1860, 1873, 
-	1890, 1907, 1924, 1941, 1958, 1971, 1984, 1997, 
-	2010, 2022, 2039, 2055, 2068, 2080, 2097, 2113, 
-	2126, 2138, 2155, 2171, 2184, 2196, 2213, 2229, 
-	2242, 2254, 2265, 2273, 2279, 2281, 2283, 2299, 
-	2307, 2310, 2318, 2330, 2343, 2356, 2368, 2379, 
-	2392, 2404, 2415, 2428, 2440, 2451, 2464, 2476, 
-	2486, 2499, 2516, 2529, 2542, 2559, 2576, 2593, 
-	2610, 2627, 2640, 2653, 2670, 2687, 2704, 2721, 
-	2738, 2751, 2764, 2781, 2798, 2815, 2832, 2849, 
-	2862, 2875, 2892, 2909, 2926, 2943, 2955, 2972, 
-	2985, 2998, 3010, 3027, 3043, 3056, 3068, 3085, 
-	3101, 3114, 3126, 3143, 3159, 3172, 3184, 3201, 
-	3217, 3230, 3242, 3253, 3261, 3267, 3269, 3271, 
-	3287, 3295, 3298, 3306, 3318, 3331, 3344, 3356, 
-	3367, 3380, 3392, 3403, 3416, 3428, 3439, 3452, 
-	3464, 3474, 3487, 3504, 3517, 3530, 3547, 3564, 
-	3581, 3598, 3615, 3628, 3641, 3658, 3675, 3692, 
-	3709, 3726, 3739, 3752, 3769, 3786, 3803, 3820, 
-	3837, 3850, 3863, 3880, 3897, 3914, 3931, 3948, 
-	3960, 3973, 3985, 3998, 4011, 4023, 4040, 4056, 
-	4069, 4081, 4098, 4114, 4127, 4139, 4156, 4172, 
-	4185, 4197, 4214, 4230, 4243, 4255, 4266, 4274, 
-	4280, 4282, 4284, 4300, 4308, 4311, 4319, 4331, 
-	4344, 4357, 4369, 4380, 4393, 4405, 4416, 4429, 
-	4441, 4452, 4465, 4477, 4487, 4500, 4517, 4530, 
-	4543, 4560, 4577, 4594, 4611, 4628, 4641, 4654, 
-	4671, 4688, 4705, 4722, 4739, 4752, 4765, 4782, 
-	4799, 4816, 4833, 4850, 4863, 4876, 4893, 4910, 
-	4927, 4944, 4961, 4974, 4991, 5007, 5024, 5036, 
-	5053, 5069, 5082, 5094, 5100, 5102, 5104, 5117, 
-	5130, 5147, 5160, 5172, 5183, 5196, 5208, 5219, 
-	5232, 5244, 5255, 5268, 5280, 5288, 5304, 5312, 
-	5315, 5323, 5335
+	946, 948, 950, 982, 1012, 1042, 1071, 1090, 
+	1120, 1150, 1179, 1198, 1228, 1258, 1287, 1306, 
+	1336, 1366, 1395, 1414, 1444, 1474, 1503, 1518, 
+	1530, 1537, 1540, 1543, 1545, 1552, 1569, 1586, 
+	1598, 1607, 1611, 1628, 1645, 1662, 1679, 1695, 
+	1710, 1727, 1743, 1758, 1775, 1791, 1806, 1823, 
+	1839, 1853, 1870, 1889, 1918, 1934, 1964, 1994, 
+	2013, 2032, 2051, 2070, 2089, 2119, 2149, 2168, 
+	2187, 2206, 2225, 2244, 2274, 2304, 2323, 2342, 
+	2361, 2380, 2399, 2429, 2459, 2478, 2497, 2516, 
+	2535, 2554, 2584, 2614, 2644, 2674, 2703, 2722, 
+	2752, 2782, 2811, 2830, 2860, 2890, 2919, 2938, 
+	2968, 2998, 3027, 3046, 3076, 3106, 3135, 3150, 
+	3162, 3169, 3172, 3175, 3177, 3184, 3201, 3218, 
+	3230, 3239, 3243, 3260, 3277, 3294, 3311, 3327, 
+	3342, 3359, 3375, 3390, 3407, 3423, 3438, 3455, 
+	3471, 3485, 3502, 3521, 3550, 3566, 3596, 3626, 
+	3645, 3664, 3683, 3702, 3721, 3751, 3781, 3800, 
+	3819, 3838, 3857, 3876, 3906, 3936, 3955, 3974, 
+	3993, 4012, 4031, 4061, 4091, 4110, 4129, 4148, 
+	4167, 4179, 4198, 4228, 4258, 4287, 4306, 4336, 
+	4366, 4395, 4414, 4444, 4474, 4503, 4522, 4552, 
+	4582, 4611, 4630, 4660, 4690, 4719, 4734, 4746, 
+	4753, 4756, 4759, 4761, 4768, 4785, 4802, 4814, 
+	4823, 4827, 4844, 4861, 4878, 4895, 4911, 4926, 
+	4943, 4959, 4974, 4991, 5007, 5022, 5039, 5055, 
+	5069, 5086, 5105, 5134, 5150, 5180, 5210, 5229, 
+	5248, 5267, 5286, 5305, 5335, 5365, 5384, 5403, 
+	5422, 5441, 5460, 5490, 5520, 5539, 5558, 5577, 
+	5596, 5615, 5645, 5675, 5694, 5713, 5732, 5751, 
+	5770, 5782, 5812, 5824, 5854, 5884, 5913, 5932, 
+	5962, 5992, 6021, 6040, 6070, 6100, 6129, 6148, 
+	6178, 6208, 6237, 6256, 6286, 6316, 6345, 6360, 
+	6372, 6379, 6382, 6385, 6387, 6394, 6411, 6428, 
+	6440, 6449, 6453, 6470, 6487, 6504, 6521, 6537, 
+	6552, 6569, 6585, 6600, 6617, 6633, 6648, 6665, 
+	6681, 6695, 6712, 6731, 6760, 6776, 6806, 6836, 
+	6855, 6874, 6893, 6912, 6931, 6961, 6991, 7010, 
+	7029, 7048, 7067, 7086, 7116, 7146, 7165, 7184, 
+	7203, 7222, 7241, 7271, 7301, 7320, 7339, 7358, 
+	7377, 7396, 7426, 7458, 7488, 7520, 7536, 7555, 
+	7585, 7615, 7644, 7651, 7654, 7657, 7659, 7666, 
+	7675, 7679, 7709, 7739, 7758, 7775, 7791, 7806, 
+	7823, 7839, 7854, 7871, 7887, 7902, 7919, 7935, 
+	7947, 7964, 7981, 7993, 8010, 8027, 8046, 8055, 
+	8059, 8066, 8069, 8072, 8074
 };
 
 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, 
@@ -346,635 +358,980 @@ static const short _indic_syllable_machi
 	162, 162, 163, 0, 164, 164, 163, 0, 
 	163, 0, 165, 166, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 165, 0, 167, 0, 168, 0, 169, 
 	0, 170, 0, 171, 162, 162, 163, 0, 
 	172, 0, 173, 0, 174, 159, 159, 160, 
 	0, 175, 0, 176, 0, 177, 156, 156, 
 	157, 0, 178, 0, 179, 0, 181, 182, 
-	183, 184, 185, 186, 81, 187, 188, 180, 
-	189, 189, 152, 190, 191, 192, 180, 194, 
-	195, 196, 197, 5, 198, 199, 200, 193, 
-	193, 37, 201, 193, 193, 181, 193, 202, 
-	195, 203, 203, 5, 198, 199, 200, 193, 
-	193, 193, 201, 193, 195, 203, 203, 5, 
-	198, 199, 200, 193, 193, 193, 201, 193, 
-	204, 193, 193, 193, 18, 205, 193, 198, 
-	199, 193, 193, 193, 193, 206, 193, 204, 
-	193, 207, 208, 209, 210, 5, 198, 199, 
-	200, 193, 193, 35, 211, 193, 193, 204, 
-	193, 212, 208, 213, 213, 5, 198, 199, 
-	200, 193, 193, 193, 211, 193, 208, 213, 
-	213, 5, 198, 199, 200, 193, 193, 193, 
-	211, 193, 214, 193, 193, 193, 18, 215, 
-	193, 198, 199, 193, 193, 193, 193, 206, 
-	193, 214, 193, 216, 217, 218, 219, 5, 
-	198, 199, 200, 193, 193, 33, 220, 193, 
-	193, 214, 193, 221, 217, 222, 222, 5, 
-	198, 199, 200, 193, 193, 193, 220, 193, 
-	217, 222, 222, 5, 198, 199, 200, 193, 
-	193, 193, 220, 193, 223, 193, 193, 193, 
-	18, 224, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 223, 193, 225, 226, 227, 
-	228, 5, 198, 199, 200, 193, 193, 31, 
-	229, 193, 193, 223, 193, 230, 226, 231, 
-	231, 5, 198, 199, 200, 193, 193, 193, 
-	229, 193, 226, 231, 231, 5, 198, 199, 
-	200, 193, 193, 193, 229, 193, 232, 193, 
-	193, 193, 18, 233, 193, 198, 199, 193, 
-	193, 193, 193, 206, 193, 232, 193, 234, 
-	235, 236, 237, 5, 198, 199, 200, 193, 
-	193, 29, 238, 193, 193, 232, 193, 239, 
-	235, 240, 240, 5, 198, 199, 200, 193, 
-	193, 193, 238, 193, 235, 240, 240, 5, 
-	198, 199, 200, 193, 193, 193, 238, 193, 
-	18, 241, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 242, 193, 193, 193, 199, 
-	193, 199, 193, 243, 193, 244, 193, 245, 
-	246, 193, 198, 199, 193, 193, 193, 3, 
-	193, 193, 193, 1, 193, 2, 193, 193, 
-	193, 193, 198, 199, 193, 198, 199, 193, 
-	244, 193, 193, 193, 193, 198, 199, 193, 
-	244, 193, 245, 193, 193, 198, 199, 193, 
-	193, 193, 3, 193, 18, 193, 247, 247, 
-	5, 198, 199, 193, 193, 193, 193, 206, 
-	193, 248, 27, 249, 250, 8, 198, 199, 
-	193, 193, 193, 193, 206, 193, 27, 249, 
-	250, 8, 198, 199, 193, 193, 193, 193, 
-	206, 193, 249, 249, 8, 198, 199, 193, 
-	193, 193, 193, 206, 193, 251, 24, 252, 
-	253, 11, 198, 199, 193, 193, 193, 193, 
-	206, 193, 24, 252, 253, 11, 198, 199, 
-	193, 193, 193, 193, 206, 193, 252, 252, 
-	11, 198, 199, 193, 193, 193, 193, 206, 
-	193, 254, 21, 255, 256, 14, 198, 199, 
-	193, 193, 193, 193, 206, 193, 21, 255, 
-	256, 14, 198, 199, 193, 193, 193, 193, 
-	206, 193, 255, 255, 14, 198, 199, 193, 
-	193, 193, 193, 206, 193, 257, 18, 193, 
-	258, 193, 198, 199, 193, 193, 193, 193, 
-	206, 193, 18, 193, 258, 193, 198, 199, 
-	193, 193, 193, 193, 206, 193, 259, 193, 
-	198, 199, 193, 193, 193, 193, 206, 193, 
-	18, 193, 193, 193, 193, 198, 199, 193, 
-	193, 193, 193, 206, 193, 235, 240, 240, 
-	5, 198, 199, 193, 193, 193, 193, 238, 
-	193, 1, 2, 193, 193, 18, 241, 193, 
-	198, 199, 193, 193, 193, 193, 206, 193, 
-	1, 193, 234, 235, 240, 240, 5, 198, 
-	199, 200, 193, 193, 193, 238, 193, 234, 
-	235, 236, 240, 5, 198, 199, 200, 193, 
-	193, 29, 238, 193, 232, 193, 260, 193, 
-	247, 247, 5, 198, 199, 193, 193, 193, 
-	193, 206, 193, 232, 193, 232, 193, 193, 
-	193, 193, 193, 193, 198, 199, 193, 193, 
-	193, 193, 206, 193, 232, 193, 232, 193, 
-	193, 193, 193, 261, 193, 198, 199, 193, 
-	193, 193, 193, 206, 193, 232, 193, 232, 
-	193, 260, 193, 193, 193, 193, 198, 199, 
-	193, 193, 193, 193, 206, 193, 232, 193, 
-	232, 2, 193, 193, 18, 233, 193, 198, 
-	199, 193, 193, 193, 193, 206, 193, 232, 
-	193, 225, 226, 231, 231, 5, 198, 199, 
-	200, 193, 193, 193, 229, 193, 225, 226, 
-	227, 231, 5, 198, 199, 200, 193, 193, 
-	31, 229, 193, 223, 193, 262, 193, 247, 
-	247, 5, 198, 199, 193, 193, 193, 193, 
-	206, 193, 223, 193, 223, 193, 193, 193, 
-	193, 193, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 223, 193, 223, 193, 193, 
-	193, 193, 263, 193, 198, 199, 193, 193, 
-	193, 193, 206, 193, 223, 193, 223, 193, 
-	262, 193, 193, 193, 193, 198, 199, 193, 
-	193, 193, 193, 206, 193, 223, 193, 223, 
-	2, 193, 193, 18, 224, 193, 198, 199, 
-	193, 193, 193, 193, 206, 193, 223, 193, 
-	216, 217, 222, 222, 5, 198, 199, 200, 
-	193, 193, 193, 220, 193, 216, 217, 218, 
-	222, 5, 198, 199, 200, 193, 193, 33, 
-	220, 193, 214, 193, 264, 193, 247, 247, 
-	5, 198, 199, 193, 193, 193, 193, 206, 
-	193, 214, 193, 214, 193, 193, 193, 193, 
-	193, 193, 198, 199, 193, 193, 193, 193, 
-	206, 193, 214, 193, 214, 193, 193, 193, 
-	193, 265, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 214, 193, 214, 193, 264, 
-	193, 193, 193, 193, 198, 199, 193, 193, 
-	193, 193, 206, 193, 214, 193, 214, 2, 
-	193, 193, 18, 215, 193, 198, 199, 193, 
-	193, 193, 193, 206, 193, 214, 193, 207, 
-	208, 213, 213, 5, 198, 199, 200, 193, 
-	193, 193, 211, 193, 207, 208, 209, 213, 
-	5, 198, 199, 200, 193, 193, 35, 211, 
-	193, 204, 193, 266, 193, 247, 247, 5, 
-	198, 199, 193, 193, 193, 193, 206, 193, 
-	204, 193, 204, 193, 193, 193, 193, 193, 
-	193, 198, 199, 193, 193, 193, 193, 206, 
-	193, 204, 193, 204, 193, 193, 193, 193, 
-	267, 193, 198, 199, 193, 193, 193, 193, 
-	206, 193, 204, 193, 204, 193, 266, 193, 
-	193, 193, 193, 198, 199, 193, 193, 193, 
-	193, 206, 193, 204, 193, 204, 2, 193, 
-	193, 18, 205, 193, 198, 199, 193, 193, 
-	193, 193, 206, 193, 204, 193, 194, 195, 
-	203, 203, 5, 198, 199, 200, 193, 193, 
-	193, 201, 193, 194, 195, 196, 203, 5, 
-	198, 199, 200, 193, 193, 37, 201, 193, 
-	269, 270, 271, 272, 43, 273, 274, 268, 
-	268, 268, 75, 275, 268, 276, 270, 277, 
-	272, 43, 273, 274, 268, 268, 268, 268, 
-	275, 268, 270, 277, 272, 43, 273, 274, 
-	268, 268, 268, 268, 275, 268, 278, 268, 
-	268, 268, 56, 279, 268, 273, 274, 268, 
-	268, 268, 268, 280, 268, 278, 268, 281, 
-	282, 283, 284, 43, 273, 274, 268, 268, 
-	268, 73, 285, 268, 268, 278, 268, 286, 
-	282, 287, 287, 43, 273, 274, 268, 268, 
-	268, 268, 285, 268, 282, 287, 287, 43, 
-	273, 274, 268, 268, 268, 268, 285, 268, 
-	288, 268, 268, 268, 56, 289, 268, 273, 
-	274, 268, 268, 268, 268, 280, 268, 288, 
-	268, 290, 291, 292, 293, 43, 273, 274, 
-	268, 268, 268, 71, 294, 268, 268, 288, 
-	268, 295, 291, 296, 296, 43, 273, 274, 
-	268, 268, 268, 268, 294, 268, 291, 296, 
-	296, 43, 273, 274, 268, 268, 268, 268, 
-	294, 268, 297, 268, 268, 268, 56, 298, 
-	268, 273, 274, 268, 268, 268, 268, 280, 
-	268, 297, 268, 299, 300, 301, 302, 43, 
-	273, 274, 268, 268, 268, 69, 303, 268, 
-	268, 297, 268, 304, 300, 305, 305, 43, 
-	273, 274, 268, 268, 268, 268, 303, 268, 
-	300, 305, 305, 43, 273, 274, 268, 268, 
-	268, 268, 303, 268, 306, 268, 268, 268, 
-	56, 307, 268, 273, 274, 268, 268, 268, 
-	268, 280, 268, 306, 268, 308, 309, 310, 
-	311, 43, 273, 274, 268, 268, 268, 67, 
-	312, 268, 268, 306, 268, 313, 309, 314, 
-	314, 43, 273, 274, 268, 268, 268, 268, 
-	312, 268, 309, 314, 314, 43, 273, 274, 
-	268, 268, 268, 268, 312, 268, 56, 315, 
-	268, 273, 274, 268, 268, 268, 268, 280, 
-	268, 273, 274, 268, 268, 268, 268, 280, 
-	268, 316, 268, 268, 268, 274, 268, 274, 
-	268, 317, 268, 318, 268, 319, 320, 268, 
-	273, 274, 268, 268, 268, 41, 268, 268, 
-	268, 39, 268, 40, 268, 268, 268, 268, 
-	273, 274, 268, 273, 274, 268, 318, 268, 
-	268, 268, 268, 273, 274, 268, 318, 268, 
-	319, 268, 268, 273, 274, 268, 268, 268, 
-	41, 268, 56, 268, 321, 321, 43, 273, 
-	274, 268, 268, 268, 268, 280, 268, 322, 
-	65, 323, 324, 46, 273, 274, 268, 268, 
-	268, 268, 280, 268, 65, 323, 324, 46, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	323, 323, 46, 273, 274, 268, 268, 268, 
-	268, 280, 268, 325, 62, 326, 327, 49, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	62, 326, 327, 49, 273, 274, 268, 268, 
-	268, 268, 280, 268, 326, 326, 49, 273, 
-	274, 268, 268, 268, 268, 280, 268, 328, 
-	59, 329, 330, 52, 273, 274, 268, 268, 
-	268, 268, 280, 268, 59, 329, 330, 52, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	329, 329, 52, 273, 274, 268, 268, 268, 
-	268, 280, 268, 331, 56, 268, 332, 268, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	56, 268, 332, 268, 273, 274, 268, 268, 
-	268, 268, 280, 268, 333, 268, 273, 274, 
-	268, 268, 268, 268, 280, 268, 56, 268, 
-	268, 268, 268, 273, 274, 268, 268, 268, 
-	268, 280, 268, 39, 40, 268, 268, 56, 
-	315, 268, 273, 274, 268, 268, 268, 268, 
-	280, 268, 39, 268, 308, 309, 314, 314, 
-	43, 273, 274, 268, 268, 268, 268, 312, 
-	268, 308, 309, 310, 314, 43, 273, 274, 
-	268, 268, 268, 67, 312, 268, 306, 268, 
-	334, 268, 321, 321, 43, 273, 274, 268, 
-	268, 268, 268, 280, 268, 306, 268, 306, 
-	268, 268, 268, 268, 268, 268, 273, 274, 
-	268, 268, 268, 268, 280, 268, 306, 268, 
-	306, 268, 268, 268, 268, 335, 268, 273, 
-	274, 268, 268, 268, 268, 280, 268, 306, 
-	268, 306, 268, 334, 268, 268, 268, 268, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	306, 268, 306, 40, 268, 268, 56, 307, 
-	268, 273, 274, 268, 268, 268, 268, 280, 
-	268, 306, 268, 299, 300, 305, 305, 43, 
-	273, 274, 268, 268, 268, 268, 303, 268, 
-	299, 300, 301, 305, 43, 273, 274, 268, 
-	268, 268, 69, 303, 268, 297, 268, 336, 
-	268, 321, 321, 43, 273, 274, 268, 268, 
-	268, 268, 280, 268, 297, 268, 297, 268, 
-	268, 268, 268, 268, 268, 273, 274, 268, 
-	268, 268, 268, 280, 268, 297, 268, 297, 
-	268, 268, 268, 268, 337, 268, 273, 274, 
-	268, 268, 268, 268, 280, 268, 297, 268, 
-	297, 268, 336, 268, 268, 268, 268, 273, 
-	274, 268, 268, 268, 268, 280, 268, 297, 
-	268, 297, 40, 268, 268, 56, 298, 268, 
-	273, 274, 268, 268, 268, 268, 280, 268, 
-	297, 268, 290, 291, 296, 296, 43, 273, 
-	274, 268, 268, 268, 268, 294, 268, 290, 
-	291, 292, 296, 43, 273, 274, 268, 268, 
-	268, 71, 294, 268, 288, 268, 338, 268, 
-	321, 321, 43, 273, 274, 268, 268, 268, 
-	268, 280, 268, 288, 268, 288, 268, 268, 
-	268, 268, 268, 268, 273, 274, 268, 268, 
-	268, 268, 280, 268, 288, 268, 288, 268, 
-	268, 268, 268, 339, 268, 273, 274, 268, 
-	268, 268, 268, 280, 268, 288, 268, 288, 
-	268, 338, 268, 268, 268, 268, 273, 274, 
-	268, 268, 268, 268, 280, 268, 288, 268, 
-	288, 40, 268, 268, 56, 289, 268, 273, 
-	274, 268, 268, 268, 268, 280, 268, 288, 
-	268, 281, 282, 287, 287, 43, 273, 274, 
-	268, 268, 268, 268, 285, 268, 281, 282, 
-	283, 287, 43, 273, 274, 268, 268, 268, 
-	73, 285, 268, 278, 268, 340, 268, 321, 
-	321, 43, 273, 274, 268, 268, 268, 268, 
-	280, 268, 278, 268, 278, 268, 268, 268, 
-	268, 268, 268, 273, 274, 268, 268, 268, 
-	268, 280, 268, 278, 268, 278, 268, 268, 
-	268, 268, 341, 268, 273, 274, 268, 268, 
-	268, 268, 280, 268, 278, 268, 278, 268, 
-	340, 268, 268, 268, 268, 273, 274, 268, 
-	268, 268, 268, 280, 268, 278, 268, 74, 
-	42, 42, 43, 268, 268, 268, 268, 268, 
-	268, 74, 268, 278, 40, 268, 268, 56, 
-	279, 268, 273, 274, 268, 268, 268, 268, 
-	280, 268, 278, 268, 269, 270, 277, 272, 
-	43, 273, 274, 268, 268, 268, 268, 275, 
-	268, 343, 184, 344, 344, 81, 187, 188, 
-	342, 342, 342, 342, 190, 342, 184, 344, 
-	344, 81, 187, 188, 342, 342, 342, 342, 
-	190, 342, 345, 342, 342, 342, 95, 346, 
-	342, 187, 188, 342, 342, 342, 342, 347, 
-	342, 345, 342, 348, 349, 350, 351, 81, 
-	187, 188, 342, 342, 342, 112, 352, 342, 
-	342, 345, 342, 353, 349, 354, 354, 81, 
-	187, 188, 342, 342, 342, 342, 352, 342, 
-	349, 354, 354, 81, 187, 188, 342, 342, 
-	342, 342, 352, 342, 355, 342, 342, 342, 
-	95, 356, 342, 187, 188, 342, 342, 342, 
-	342, 347, 342, 355, 342, 357, 358, 359, 
-	360, 81, 187, 188, 342, 342, 342, 110, 
-	361, 342, 342, 355, 342, 362, 358, 363, 
-	363, 81, 187, 188, 342, 342, 342, 342, 
-	361, 342, 358, 363, 363, 81, 187, 188, 
-	342, 342, 342, 342, 361, 342, 364, 342, 
-	342, 342, 95, 365, 342, 187, 188, 342, 
-	342, 342, 342, 347, 342, 364, 342, 366, 
-	367, 368, 369, 81, 187, 188, 342, 342, 
-	342, 108, 370, 342, 342, 364, 342, 371, 
-	367, 372, 372, 81, 187, 188, 342, 342, 
-	342, 342, 370, 342, 367, 372, 372, 81, 
-	187, 188, 342, 342, 342, 342, 370, 342, 
-	373, 342, 342, 342, 95, 374, 342, 187, 
-	188, 342, 342, 342, 342, 347, 342, 373, 
-	342, 375, 376, 377, 378, 81, 187, 188, 
-	342, 342, 342, 106, 379, 342, 342, 373, 
-	342, 380, 376, 381, 381, 81, 187, 188, 
-	342, 342, 342, 342, 379, 342, 376, 381, 
-	381, 81, 187, 188, 342, 342, 342, 342, 
-	379, 342, 95, 382, 342, 187, 188, 342, 
-	342, 342, 342, 347, 342, 187, 188, 342, 
-	342, 342, 342, 347, 342, 383, 342, 342, 
-	342, 188, 342, 188, 342, 384, 342, 385, 
-	342, 386, 387, 342, 187, 188, 342, 342, 
-	342, 79, 342, 342, 342, 77, 342, 78, 
-	342, 342, 342, 342, 187, 188, 342, 187, 
-	188, 342, 385, 342, 342, 342, 342, 187, 
-	188, 342, 385, 342, 386, 342, 342, 187, 
-	188, 342, 342, 342, 79, 342, 95, 342, 
-	388, 388, 81, 187, 188, 342, 342, 342, 
-	342, 347, 342, 389, 104, 390, 391, 85, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	104, 390, 391, 85, 187, 188, 342, 342, 
-	342, 342, 347, 342, 390, 390, 85, 187, 
-	188, 342, 342, 342, 342, 347, 342, 392, 
-	101, 393, 394, 88, 187, 188, 342, 342, 
-	342, 342, 347, 342, 101, 393, 394, 88, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	393, 393, 88, 187, 188, 342, 342, 342, 
-	342, 347, 342, 395, 98, 396, 397, 91, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	98, 396, 397, 91, 187, 188, 342, 342, 
-	342, 342, 347, 342, 396, 396, 91, 187, 
-	188, 342, 342, 342, 342, 347, 342, 398, 
-	95, 342, 399, 342, 187, 188, 342, 342, 
-	342, 342, 347, 342, 95, 342, 399, 342, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	400, 342, 187, 188, 342, 342, 342, 342, 
-	347, 342, 95, 342, 342, 342, 342, 187, 
-	188, 342, 342, 342, 342, 347, 342, 77, 
-	78, 342, 342, 95, 382, 342, 187, 188, 
-	342, 342, 342, 342, 347, 342, 77, 342, 
-	375, 376, 381, 381, 81, 187, 188, 342, 
-	342, 342, 342, 379, 342, 375, 376, 377, 
-	381, 81, 187, 188, 342, 342, 342, 106, 
-	379, 342, 373, 342, 401, 342, 388, 388, 
-	81, 187, 188, 342, 342, 342, 342, 347, 
-	342, 373, 342, 373, 342, 342, 342, 342, 
-	342, 342, 187, 188, 342, 342, 342, 342, 
-	347, 342, 373, 342, 373, 342, 342, 342, 
-	342, 402, 342, 187, 188, 342, 342, 342, 
-	342, 347, 342, 373, 342, 373, 342, 401, 
-	342, 342, 342, 342, 187, 188, 342, 342, 
-	342, 342, 347, 342, 373, 342, 373, 78, 
-	342, 342, 95, 374, 342, 187, 188, 342, 
-	342, 342, 342, 347, 342, 373, 342, 366, 
-	367, 372, 372, 81, 187, 188, 342, 342, 
-	342, 342, 370, 342, 366, 367, 368, 372, 
-	81, 187, 188, 342, 342, 342, 108, 370, 
-	342, 364, 342, 403, 342, 388, 388, 81, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	364, 342, 364, 342, 342, 342, 342, 342, 
-	342, 187, 188, 342, 342, 342, 342, 347, 
-	342, 364, 342, 364, 342, 342, 342, 342, 
-	404, 342, 187, 188, 342, 342, 342, 342, 
-	347, 342, 364, 342, 364, 342, 403, 342, 
-	342, 342, 342, 187, 188, 342, 342, 342, 
-	342, 347, 342, 364, 342, 364, 78, 342, 
-	342, 95, 365, 342, 187, 188, 342, 342, 
-	342, 342, 347, 342, 364, 342, 357, 358, 
-	363, 363, 81, 187, 188, 342, 342, 342, 
-	342, 361, 342, 357, 358, 359, 363, 81, 
-	187, 188, 342, 342, 342, 110, 361, 342, 
-	355, 342, 405, 342, 388, 388, 81, 187, 
-	188, 342, 342, 342, 342, 347, 342, 355, 
-	342, 355, 342, 342, 342, 342, 342, 342, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	355, 342, 355, 342, 342, 342, 342, 406, 
-	342, 187, 188, 342, 342, 342, 342, 347, 
-	342, 355, 342, 355, 342, 405, 342, 342, 
-	342, 342, 187, 188, 342, 342, 342, 342, 
-	347, 342, 355, 342, 355, 78, 342, 342, 
-	95, 356, 342, 187, 188, 342, 342, 342, 
-	342, 347, 342, 355, 342, 348, 349, 354, 
-	354, 81, 187, 188, 342, 342, 342, 342, 
-	352, 342, 348, 349, 350, 354, 81, 187, 
-	188, 342, 342, 342, 112, 352, 342, 345, 
-	342, 407, 342, 388, 388, 81, 187, 188, 
-	342, 342, 342, 342, 347, 342, 345, 342, 
-	345, 342, 342, 342, 342, 342, 342, 187, 
-	188, 342, 342, 342, 342, 347, 342, 345, 
-	342, 345, 342, 342, 342, 342, 408, 342, 
-	187, 188, 342, 342, 342, 342, 347, 342, 
-	345, 342, 345, 342, 407, 342, 342, 342, 
-	342, 187, 188, 342, 342, 342, 342, 347, 
-	342, 345, 342, 345, 78, 342, 342, 95, 
-	346, 342, 187, 188, 342, 342, 342, 342, 
-	347, 342, 345, 342, 113, 80, 80, 81, 
-	409, 409, 409, 409, 409, 152, 113, 409, 
-	183, 184, 344, 344, 81, 187, 188, 342, 
-	342, 342, 342, 190, 342, 113, 80, 80, 
-	81, 409, 409, 409, 409, 409, 409, 113, 
-	409, 411, 412, 413, 414, 119, 415, 416, 
-	410, 410, 410, 151, 417, 410, 418, 412, 
-	414, 414, 119, 415, 416, 410, 410, 410, 
-	410, 417, 410, 412, 414, 414, 119, 415, 
-	416, 410, 410, 410, 410, 417, 410, 419, 
-	410, 410, 410, 132, 420, 410, 415, 416, 
-	410, 410, 410, 410, 421, 410, 419, 410, 
-	422, 423, 424, 425, 119, 415, 416, 410, 
-	410, 410, 149, 426, 410, 410, 419, 410, 
-	427, 423, 428, 428, 119, 415, 416, 410, 
-	410, 410, 410, 426, 410, 423, 428, 428, 
-	119, 415, 416, 410, 410, 410, 410, 426, 
-	410, 429, 410, 410, 410, 132, 430, 410, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	429, 410, 431, 432, 433, 434, 119, 415, 
-	416, 410, 410, 410, 147, 435, 410, 410, 
-	429, 410, 436, 432, 437, 437, 119, 415, 
-	416, 410, 410, 410, 410, 435, 410, 432, 
-	437, 437, 119, 415, 416, 410, 410, 410, 
-	410, 435, 410, 438, 410, 410, 410, 132, 
-	439, 410, 415, 416, 410, 410, 410, 410, 
-	421, 410, 438, 410, 440, 441, 442, 443, 
-	119, 415, 416, 410, 410, 410, 145, 444, 
-	410, 410, 438, 410, 445, 441, 446, 446, 
-	119, 415, 416, 410, 410, 410, 410, 444, 
-	410, 441, 446, 446, 119, 415, 416, 410, 
-	410, 410, 410, 444, 410, 447, 410, 410, 
-	410, 132, 448, 410, 415, 416, 410, 410, 
-	410, 410, 421, 410, 447, 410, 449, 450, 
-	451, 452, 119, 415, 416, 410, 410, 410, 
-	143, 453, 410, 410, 447, 410, 454, 450, 
-	455, 455, 119, 415, 416, 410, 410, 410, 
-	410, 453, 410, 450, 455, 455, 119, 415, 
-	416, 410, 410, 410, 410, 453, 410, 132, 
-	456, 410, 415, 416, 410, 410, 410, 410, 
-	421, 410, 415, 416, 410, 410, 410, 410, 
-	421, 410, 457, 410, 410, 410, 416, 410, 
-	416, 410, 458, 410, 459, 410, 460, 461, 
-	410, 415, 416, 410, 410, 410, 117, 410, 
-	410, 410, 115, 410, 116, 410, 410, 410, 
-	410, 415, 416, 410, 415, 416, 410, 459, 
-	410, 410, 410, 410, 415, 416, 410, 459, 
-	410, 460, 410, 410, 415, 416, 410, 410, 
-	410, 117, 410, 132, 410, 462, 462, 119, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	463, 141, 464, 465, 122, 415, 416, 410, 
-	410, 410, 410, 421, 410, 141, 464, 465, 
-	122, 415, 416, 410, 410, 410, 410, 421, 
-	410, 464, 464, 122, 415, 416, 410, 410, 
-	410, 410, 421, 410, 466, 138, 467, 468, 
-	125, 415, 416, 410, 410, 410, 410, 421, 
-	410, 138, 467, 468, 125, 415, 416, 410, 
-	410, 410, 410, 421, 410, 467, 467, 125, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	469, 135, 470, 471, 128, 415, 416, 410, 
-	410, 410, 410, 421, 410, 135, 470, 471, 
-	128, 415, 416, 410, 410, 410, 410, 421, 
-	410, 470, 470, 128, 415, 416, 410, 410, 
-	410, 410, 421, 410, 472, 132, 410, 473, 
-	410, 415, 416, 410, 410, 410, 410, 421, 
-	410, 132, 410, 473, 410, 415, 416, 410, 
-	410, 410, 410, 421, 410, 474, 410, 415, 
-	416, 410, 410, 410, 410, 421, 410, 132, 
-	410, 410, 410, 410, 415, 416, 410, 410, 
-	410, 410, 421, 410, 115, 116, 410, 410, 
-	132, 456, 410, 415, 416, 410, 410, 410, 
-	410, 421, 410, 115, 410, 449, 450, 455, 
-	455, 119, 415, 416, 410, 410, 410, 410, 
-	453, 410, 449, 450, 451, 455, 119, 415, 
-	416, 410, 410, 410, 143, 453, 410, 447, 
-	410, 475, 410, 462, 462, 119, 415, 416, 
-	410, 410, 410, 410, 421, 410, 447, 410, 
-	447, 410, 410, 410, 410, 410, 410, 415, 
-	416, 410, 410, 410, 410, 421, 410, 447, 
-	410, 447, 410, 410, 410, 410, 476, 410, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	447, 410, 447, 410, 475, 410, 410, 410, 
-	410, 415, 416, 410, 410, 410, 410, 421, 
-	410, 447, 410, 447, 116, 410, 410, 132, 
-	448, 410, 415, 416, 410, 410, 410, 410, 
-	421, 410, 447, 410, 440, 441, 446, 446, 
-	119, 415, 416, 410, 410, 410, 410, 444, 
-	410, 440, 441, 442, 446, 119, 415, 416, 
-	410, 410, 410, 145, 444, 410, 438, 410, 
-	477, 410, 462, 462, 119, 415, 416, 410, 
-	410, 410, 410, 421, 410, 438, 410, 438, 
-	410, 410, 410, 410, 410, 410, 415, 416, 
-	410, 410, 410, 410, 421, 410, 438, 410, 
-	438, 410, 410, 410, 410, 478, 410, 415, 
-	416, 410, 410, 410, 410, 421, 410, 438, 
-	410, 438, 410, 477, 410, 410, 410, 410, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	438, 410, 438, 116, 410, 410, 132, 439, 
-	410, 415, 416, 410, 410, 410, 410, 421, 
-	410, 438, 410, 431, 432, 437, 437, 119, 
-	415, 416, 410, 410, 410, 410, 435, 410, 
-	431, 432, 433, 437, 119, 415, 416, 410, 
-	410, 410, 147, 435, 410, 429, 410, 479, 
-	410, 462, 462, 119, 415, 416, 410, 410, 
-	410, 410, 421, 410, 429, 410, 429, 410, 
-	410, 410, 410, 410, 410, 415, 416, 410, 
-	410, 410, 410, 421, 410, 429, 410, 429, 
-	410, 410, 410, 410, 480, 410, 415, 416, 
-	410, 410, 410, 410, 421, 410, 429, 410, 
-	429, 410, 479, 410, 410, 410, 410, 415, 
-	416, 410, 410, 410, 410, 421, 410, 429, 
-	410, 429, 116, 410, 410, 132, 430, 410, 
-	415, 416, 410, 410, 410, 410, 421, 410, 
-	429, 410, 422, 423, 428, 428, 119, 415, 
-	416, 410, 410, 410, 410, 426, 410, 422, 
-	423, 424, 428, 119, 415, 416, 410, 410, 
-	410, 149, 426, 410, 419, 410, 481, 410, 
-	462, 462, 119, 415, 416, 410, 410, 410, 
-	410, 421, 410, 419, 410, 419, 410, 410, 
-	410, 410, 410, 410, 415, 416, 410, 410, 
-	410, 410, 421, 410, 419, 410, 419, 410, 
-	410, 410, 410, 482, 410, 415, 416, 410, 
-	410, 410, 410, 421, 410, 419, 410, 419, 
-	410, 481, 410, 410, 410, 410, 415, 416, 
-	410, 410, 410, 410, 421, 410, 419, 410, 
-	419, 116, 410, 410, 132, 420, 410, 415, 
-	416, 410, 410, 410, 410, 421, 410, 419, 
-	410, 411, 412, 414, 414, 119, 415, 416, 
-	410, 410, 410, 410, 417, 410, 181, 182, 
-	183, 184, 483, 344, 81, 187, 188, 342, 
-	189, 189, 152, 190, 342, 181, 342, 194, 
-	484, 196, 197, 5, 198, 199, 200, 193, 
-	193, 37, 201, 193, 193, 181, 193, 204, 
-	182, 183, 184, 485, 486, 81, 487, 488, 
-	193, 189, 189, 152, 489, 193, 204, 193, 
-	113, 80, 80, 81, 198, 199, 193, 193, 
-	193, 152, 490, 193, 491, 2, 342, 342, 
-	342, 408, 342, 187, 188, 342, 342, 342, 
-	342, 347, 342, 491, 342, 492, 349, 493, 
-	494, 81, 487, 488, 193, 193, 193, 153, 
-	352, 193, 193, 491, 193, 495, 349, 354, 
-	354, 81, 487, 488, 193, 193, 193, 193, 
-	352, 193, 349, 354, 354, 81, 487, 488, 
-	193, 193, 193, 193, 352, 193, 496, 193, 
-	193, 193, 488, 193, 488, 193, 243, 193, 
-	492, 349, 354, 354, 81, 487, 488, 193, 
-	193, 193, 193, 352, 193, 492, 349, 493, 
-	354, 81, 487, 488, 193, 193, 193, 153, 
-	352, 193, 204, 193, 266, 113, 497, 497, 
-	155, 198, 199, 193, 193, 193, 193, 490, 
-	193, 204, 193, 498, 179, 499, 500, 157, 
-	487, 488, 193, 193, 193, 193, 501, 193, 
-	179, 499, 500, 157, 487, 488, 193, 193, 
-	193, 193, 501, 193, 499, 499, 157, 487, 
-	488, 193, 193, 193, 193, 501, 193, 502, 
-	176, 503, 504, 160, 487, 488, 193, 193, 
-	193, 193, 501, 193, 176, 503, 504, 160, 
-	487, 488, 193, 193, 193, 193, 501, 193, 
-	503, 503, 160, 487, 488, 193, 193, 193, 
-	193, 501, 193, 505, 173, 506, 507, 163, 
-	487, 488, 193, 193, 193, 193, 501, 193, 
-	173, 506, 507, 163, 487, 488, 193, 193, 
-	193, 193, 501, 193, 506, 506, 163, 487, 
-	488, 193, 193, 193, 193, 501, 193, 508, 
-	170, 193, 509, 193, 487, 488, 193, 193, 
-	193, 193, 501, 193, 170, 193, 509, 193, 
-	487, 488, 193, 193, 193, 193, 501, 193, 
-	487, 488, 193, 193, 193, 193, 501, 193, 
-	510, 193, 511, 512, 193, 487, 488, 193, 
-	193, 193, 167, 193, 193, 193, 165, 193, 
-	166, 193, 193, 193, 193, 487, 488, 193, 
-	487, 488, 193, 510, 193, 193, 193, 193, 
-	487, 488, 193, 510, 193, 511, 193, 193, 
-	487, 488, 193, 193, 193, 167, 193, 491, 
-	166, 342, 342, 95, 346, 342, 187, 188, 
-	342, 342, 342, 342, 347, 342, 491, 342, 
-	0
+	183, 184, 185, 186, 81, 187, 188, 189, 
+	190, 190, 152, 191, 192, 193, 194, 195, 
+	180, 180, 180, 180, 180, 180, 180, 180, 
+	180, 180, 180, 180, 196, 180, 198, 199, 
+	200, 201, 5, 202, 203, 204, 197, 197, 
+	37, 205, 197, 197, 206, 207, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 208, 197, 209, 199, 210, 210, 
+	5, 202, 203, 204, 197, 197, 197, 205, 
+	197, 197, 206, 207, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	208, 197, 199, 210, 210, 5, 202, 203, 
+	204, 197, 197, 197, 205, 197, 197, 206, 
+	207, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 208, 197, 211, 
+	197, 197, 197, 18, 212, 197, 202, 203, 
+	204, 197, 197, 197, 213, 197, 211, 197, 
+	207, 197, 214, 215, 216, 217, 5, 202, 
+	203, 204, 197, 197, 35, 218, 197, 197, 
+	206, 207, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 208, 197, 
+	219, 215, 220, 220, 5, 202, 203, 204, 
+	197, 197, 197, 218, 197, 197, 206, 207, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 208, 197, 215, 220, 
+	220, 5, 202, 203, 204, 197, 197, 197, 
+	218, 197, 197, 206, 207, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 208, 197, 221, 197, 197, 197, 18, 
+	222, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 221, 197, 207, 197, 223, 224, 
+	225, 226, 5, 202, 203, 204, 197, 197, 
+	33, 227, 197, 197, 206, 207, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 208, 197, 228, 224, 229, 229, 
+	5, 202, 203, 204, 197, 197, 197, 227, 
+	197, 197, 206, 207, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	208, 197, 224, 229, 229, 5, 202, 203, 
+	204, 197, 197, 197, 227, 197, 197, 206, 
+	207, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 208, 197, 230, 
+	197, 197, 197, 18, 231, 197, 202, 203, 
+	204, 197, 197, 197, 213, 197, 230, 197, 
+	207, 197, 232, 233, 234, 235, 5, 202, 
+	203, 204, 197, 197, 31, 236, 197, 197, 
+	206, 207, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 208, 197, 
+	237, 233, 238, 238, 5, 202, 203, 204, 
+	197, 197, 197, 236, 197, 197, 206, 207, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 208, 197, 233, 238, 
+	238, 5, 202, 203, 204, 197, 197, 197, 
+	236, 197, 197, 206, 207, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 208, 197, 239, 197, 197, 197, 18, 
+	240, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 239, 197, 207, 197, 241, 242, 
+	243, 244, 5, 202, 203, 204, 197, 197, 
+	29, 245, 197, 197, 206, 207, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 208, 197, 246, 242, 247, 247, 
+	5, 202, 203, 204, 197, 197, 197, 245, 
+	197, 197, 206, 207, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	208, 197, 242, 247, 247, 5, 202, 203, 
+	204, 197, 197, 197, 245, 197, 197, 206, 
+	207, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 208, 197, 18, 
+	248, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 202, 203, 
+	204, 197, 197, 197, 213, 197, 197, 197, 
+	207, 197, 249, 197, 197, 250, 203, 204, 
+	197, 203, 204, 197, 203, 251, 197, 203, 
+	197, 249, 197, 197, 197, 203, 204, 197, 
+	252, 197, 253, 254, 197, 202, 203, 204, 
+	197, 197, 3, 197, 197, 197, 197, 207, 
+	197, 2, 197, 197, 197, 197, 202, 203, 
+	204, 197, 197, 197, 197, 197, 197, 197, 
+	207, 197, 202, 203, 204, 197, 197, 197, 
+	197, 197, 197, 197, 207, 197, 255, 197, 
+	197, 197, 197, 202, 203, 204, 197, 202, 
+	203, 204, 197, 252, 197, 197, 197, 197, 
+	202, 203, 204, 197, 197, 197, 197, 197, 
+	197, 197, 207, 197, 252, 197, 253, 197, 
+	197, 202, 203, 204, 197, 197, 3, 197, 
+	197, 197, 197, 207, 197, 18, 197, 256, 
+	256, 5, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 257, 27, 
+	258, 259, 8, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 27, 
+	258, 259, 8, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 258, 
+	258, 8, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 260, 24, 
+	261, 262, 11, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 24, 
+	261, 262, 11, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 261, 
+	261, 11, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 263, 21, 
+	264, 265, 14, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 21, 
+	264, 265, 14, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 264, 
+	264, 14, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 266, 18, 
+	197, 267, 197, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 18, 
+	197, 267, 197, 202, 203, 204, 197, 197, 
+	197, 213, 197, 197, 197, 207, 197, 268, 
+	197, 202, 203, 204, 197, 197, 197, 213, 
+	197, 197, 197, 207, 197, 18, 197, 197, 
+	197, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 197, 197, 207, 197, 1, 2, 
+	197, 197, 18, 248, 197, 202, 203, 204, 
+	197, 197, 197, 213, 197, 1, 197, 207, 
+	197, 242, 247, 247, 5, 202, 203, 204, 
+	197, 197, 197, 245, 197, 197, 197, 207, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 208, 197, 242, 247, 
+	247, 5, 202, 203, 204, 197, 197, 197, 
+	245, 197, 197, 197, 207, 197, 241, 242, 
+	247, 247, 5, 202, 203, 204, 197, 197, 
+	197, 245, 197, 197, 206, 207, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 208, 197, 241, 242, 243, 247, 
+	5, 202, 203, 204, 197, 197, 29, 245, 
+	197, 197, 206, 207, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	208, 197, 239, 197, 269, 197, 256, 256, 
+	5, 202, 203, 204, 197, 197, 197, 213, 
+	197, 239, 197, 207, 197, 239, 197, 197, 
+	197, 197, 197, 197, 202, 203, 204, 197, 
+	197, 197, 213, 197, 239, 197, 207, 197, 
+	239, 197, 197, 197, 197, 270, 197, 202, 
+	203, 204, 197, 197, 197, 213, 197, 239, 
+	197, 207, 197, 239, 197, 269, 197, 197, 
+	197, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 239, 197, 207, 197, 239, 2, 
+	197, 197, 18, 240, 197, 202, 203, 204, 
+	197, 197, 197, 213, 197, 239, 197, 207, 
+	197, 232, 233, 238, 238, 5, 202, 203, 
+	204, 197, 197, 197, 236, 197, 197, 206, 
+	207, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 208, 197, 232, 
+	233, 234, 238, 5, 202, 203, 204, 197, 
+	197, 31, 236, 197, 197, 206, 207, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 208, 197, 230, 197, 271, 
+	197, 256, 256, 5, 202, 203, 204, 197, 
+	197, 197, 213, 197, 230, 197, 207, 197, 
+	230, 197, 197, 197, 197, 197, 197, 202, 
+	203, 204, 197, 197, 197, 213, 197, 230, 
+	197, 207, 197, 230, 197, 197, 197, 197, 
+	272, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 230, 197, 207, 197, 230, 197, 
+	271, 197, 197, 197, 197, 202, 203, 204, 
+	197, 197, 197, 213, 197, 230, 197, 207, 
+	197, 230, 2, 197, 197, 18, 231, 197, 
+	202, 203, 204, 197, 197, 197, 213, 197, 
+	230, 197, 207, 197, 223, 224, 229, 229, 
+	5, 202, 203, 204, 197, 197, 197, 227, 
+	197, 197, 206, 207, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	208, 197, 223, 224, 225, 229, 5, 202, 
+	203, 204, 197, 197, 33, 227, 197, 197, 
+	206, 207, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 208, 197, 
+	221, 197, 273, 197, 256, 256, 5, 202, 
+	203, 204, 197, 197, 197, 213, 197, 221, 
+	197, 207, 197, 221, 197, 197, 197, 197, 
+	197, 197, 202, 203, 204, 197, 197, 197, 
+	213, 197, 221, 197, 207, 197, 221, 197, 
+	197, 197, 197, 274, 197, 202, 203, 204, 
+	197, 197, 197, 213, 197, 221, 197, 207, 
+	197, 221, 197, 273, 197, 197, 197, 197, 
+	202, 203, 204, 197, 197, 197, 213, 197, 
+	221, 197, 207, 197, 221, 2, 197, 197, 
+	18, 222, 197, 202, 203, 204, 197, 197, 
+	197, 213, 197, 221, 197, 207, 197, 214, 
+	215, 220, 220, 5, 202, 203, 204, 197, 
+	197, 197, 218, 197, 197, 206, 207, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 208, 197, 214, 215, 216, 
+	220, 5, 202, 203, 204, 197, 197, 35, 
+	218, 197, 197, 206, 207, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 208, 197, 211, 197, 275, 197, 256, 
+	256, 5, 202, 203, 204, 197, 197, 197, 
+	213, 197, 211, 197, 207, 197, 211, 197, 
+	197, 197, 197, 197, 197, 202, 203, 204, 
+	197, 197, 197, 213, 197, 211, 197, 207, 
+	197, 211, 197, 197, 197, 197, 276, 197, 
+	202, 203, 204, 197, 197, 197, 213, 197, 
+	211, 197, 207, 197, 211, 197, 275, 197, 
+	197, 197, 197, 202, 203, 204, 197, 197, 
+	197, 213, 197, 211, 197, 207, 197, 211, 
+	2, 197, 197, 18, 212, 197, 202, 203, 
+	204, 197, 197, 197, 213, 197, 211, 197, 
+	207, 197, 198, 199, 210, 210, 5, 202, 
+	203, 204, 197, 197, 197, 205, 197, 197, 
+	206, 207, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 208, 197, 
+	198, 199, 200, 210, 5, 202, 203, 204, 
+	197, 197, 37, 205, 197, 197, 206, 207, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 208, 197, 278, 279, 
+	280, 281, 43, 282, 283, 284, 277, 277, 
+	75, 285, 277, 277, 286, 287, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 288, 277, 289, 279, 290, 281, 
+	43, 282, 283, 284, 277, 277, 277, 285, 
+	277, 277, 286, 287, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	288, 277, 279, 290, 281, 43, 282, 283, 
+	284, 277, 277, 277, 285, 277, 277, 286, 
+	287, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 288, 277, 291, 
+	277, 277, 277, 56, 292, 277, 282, 283, 
+	284, 277, 277, 277, 293, 277, 291, 277, 
+	287, 277, 294, 295, 296, 297, 43, 282, 
+	283, 284, 277, 277, 73, 298, 277, 277, 
+	286, 287, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 288, 277, 
+	299, 295, 300, 300, 43, 282, 283, 284, 
+	277, 277, 277, 298, 277, 277, 286, 287, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 288, 277, 295, 300, 
+	300, 43, 282, 283, 284, 277, 277, 277, 
+	298, 277, 277, 286, 287, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 288, 277, 301, 277, 277, 277, 56, 
+	302, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 301, 277, 287, 277, 303, 304, 
+	305, 306, 43, 282, 283, 284, 277, 277, 
+	71, 307, 277, 277, 286, 287, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 288, 277, 308, 304, 309, 309, 
+	43, 282, 283, 284, 277, 277, 277, 307, 
+	277, 277, 286, 287, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	288, 277, 304, 309, 309, 43, 282, 283, 
+	284, 277, 277, 277, 307, 277, 277, 286, 
+	287, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 288, 277, 310, 
+	277, 277, 277, 56, 311, 277, 282, 283, 
+	284, 277, 277, 277, 293, 277, 310, 277, 
+	287, 277, 312, 313, 314, 315, 43, 282, 
+	283, 284, 277, 277, 69, 316, 277, 277, 
+	286, 287, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 288, 277, 
+	317, 313, 318, 318, 43, 282, 283, 284, 
+	277, 277, 277, 316, 277, 277, 286, 287, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 288, 277, 313, 318, 
+	318, 43, 282, 283, 284, 277, 277, 277, 
+	316, 277, 277, 286, 287, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 288, 277, 319, 277, 277, 277, 56, 
+	320, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 319, 277, 287, 277, 321, 322, 
+	323, 324, 43, 282, 283, 284, 277, 277, 
+	67, 325, 277, 277, 286, 287, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 288, 277, 326, 322, 327, 327, 
+	43, 282, 283, 284, 277, 277, 277, 325, 
+	277, 277, 286, 287, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	288, 277, 322, 327, 327, 43, 282, 283, 
+	284, 277, 277, 277, 325, 277, 277, 286, 
+	287, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 288, 277, 56, 
+	328, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 282, 283, 
+	284, 277, 277, 277, 293, 277, 277, 277, 
+	287, 277, 329, 277, 277, 330, 283, 284, 
+	277, 283, 284, 277, 283, 331, 277, 283, 
+	277, 329, 277, 277, 277, 283, 284, 277, 
+	332, 277, 333, 334, 277, 282, 283, 284, 
+	277, 277, 41, 277, 277, 277, 277, 287, 
+	277, 40, 277, 277, 277, 277, 282, 283, 
+	284, 277, 277, 277, 277, 277, 277, 277, 
+	287, 277, 282, 283, 284, 277, 277, 277, 
+	277, 277, 277, 277, 287, 277, 335, 277, 
+	277, 277, 277, 282, 283, 284, 277, 282, 
+	283, 284, 277, 332, 277, 277, 277, 277, 
+	282, 283, 284, 277, 277, 277, 277, 277, 
+	277, 277, 287, 277, 332, 277, 333, 277, 
+	277, 282, 283, 284, 277, 277, 41, 277, 
+	277, 277, 277, 287, 277, 56, 277, 336, 
+	336, 43, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 337, 65, 
+	338, 339, 46, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 65, 
+	338, 339, 46, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 338, 
+	338, 46, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 340, 62, 
+	341, 342, 49, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 62, 
+	341, 342, 49, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 341, 
+	341, 49, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 343, 59, 
+	344, 345, 52, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 59, 
+	344, 345, 52, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 344, 
+	344, 52, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 346, 56, 
+	277, 347, 277, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 56, 
+	277, 347, 277, 282, 283, 284, 277, 277, 
+	277, 293, 277, 277, 277, 287, 277, 348, 
+	277, 282, 283, 284, 277, 277, 277, 293, 
+	277, 277, 277, 287, 277, 56, 277, 277, 
+	277, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 277, 277, 287, 277, 39, 40, 
+	277, 277, 56, 328, 277, 282, 283, 284, 
+	277, 277, 277, 293, 277, 39, 277, 287, 
+	277, 322, 327, 327, 43, 282, 283, 284, 
+	277, 277, 277, 325, 277, 277, 277, 287, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 288, 277, 322, 327, 
+	327, 43, 282, 283, 284, 277, 277, 277, 
+	325, 277, 277, 277, 287, 277, 321, 322, 
+	327, 327, 43, 282, 283, 284, 277, 277, 
+	277, 325, 277, 277, 286, 287, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 288, 277, 321, 322, 323, 327, 
+	43, 282, 283, 284, 277, 277, 67, 325, 
+	277, 277, 286, 287, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	288, 277, 319, 277, 349, 277, 336, 336, 
+	43, 282, 283, 284, 277, 277, 277, 293, 
+	277, 319, 277, 287, 277, 319, 277, 277, 
+	277, 277, 277, 277, 282, 283, 284, 277, 
+	277, 277, 293, 277, 319, 277, 287, 277, 
+	319, 277, 277, 277, 277, 350, 277, 282, 
+	283, 284, 277, 277, 277, 293, 277, 319, 
+	277, 287, 277, 319, 277, 349, 277, 277, 
+	277, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 319, 277, 287, 277, 319, 40, 
+	277, 277, 56, 320, 277, 282, 283, 284, 
+	277, 277, 277, 293, 277, 319, 277, 287, 
+	277, 312, 313, 318, 318, 43, 282, 283, 
+	284, 277, 277, 277, 316, 277, 277, 286, 
+	287, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 288, 277, 312, 
+	313, 314, 318, 43, 282, 283, 284, 277, 
+	277, 69, 316, 277, 277, 286, 287, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 288, 277, 310, 277, 351, 
+	277, 336, 336, 43, 282, 283, 284, 277, 
+	277, 277, 293, 277, 310, 277, 287, 277, 
+	310, 277, 277, 277, 277, 277, 277, 282, 
+	283, 284, 277, 277, 277, 293, 277, 310, 
+	277, 287, 277, 310, 277, 277, 277, 277, 
+	352, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 310, 277, 287, 277, 310, 277, 
+	351, 277, 277, 277, 277, 282, 283, 284, 
+	277, 277, 277, 293, 277, 310, 277, 287, 
+	277, 310, 40, 277, 277, 56, 311, 277, 
+	282, 283, 284, 277, 277, 277, 293, 277, 
+	310, 277, 287, 277, 303, 304, 309, 309, 
+	43, 282, 283, 284, 277, 277, 277, 307, 
+	277, 277, 286, 287, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	288, 277, 303, 304, 305, 309, 43, 282, 
+	283, 284, 277, 277, 71, 307, 277, 277, 
+	286, 287, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 288, 277, 
+	301, 277, 353, 277, 336, 336, 43, 282, 
+	283, 284, 277, 277, 277, 293, 277, 301, 
+	277, 287, 277, 301, 277, 277, 277, 277, 
+	277, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 301, 277, 287, 277, 301, 277, 
+	277, 277, 277, 354, 277, 282, 283, 284, 
+	277, 277, 277, 293, 277, 301, 277, 287, 
+	277, 301, 277, 353, 277, 277, 277, 277, 
+	282, 283, 284, 277, 277, 277, 293, 277, 
+	301, 277, 287, 277, 301, 40, 277, 277, 
+	56, 302, 277, 282, 283, 284, 277, 277, 
+	277, 293, 277, 301, 277, 287, 277, 294, 
+	295, 300, 300, 43, 282, 283, 284, 277, 
+	277, 277, 298, 277, 277, 286, 287, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 277, 288, 277, 294, 295, 296, 
+	300, 43, 282, 283, 284, 277, 277, 73, 
+	298, 277, 277, 286, 287, 277, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 288, 277, 291, 277, 355, 277, 336, 
+	336, 43, 282, 283, 284, 277, 277, 277, 
+	293, 277, 291, 277, 287, 277, 291, 277, 
+	277, 277, 277, 277, 277, 282, 283, 284, 
+	277, 277, 277, 293, 277, 291, 277, 287, 
+	277, 291, 277, 277, 277, 277, 356, 277, 
+	282, 283, 284, 277, 277, 277, 293, 277, 
+	291, 277, 287, 277, 291, 277, 355, 277, 
+	277, 277, 277, 282, 283, 284, 277, 277, 
+	277, 293, 277, 291, 277, 287, 277, 74, 
+	42, 42, 43, 277, 277, 277, 277, 277, 
+	277, 74, 277, 291, 40, 277, 277, 56, 
+	292, 277, 282, 283, 284, 277, 277, 277, 
+	293, 277, 291, 277, 287, 277, 278, 279, 
+	290, 281, 43, 282, 283, 284, 277, 277, 
+	277, 285, 277, 277, 286, 287, 277, 277, 
+	277, 277, 277, 277, 277, 277, 277, 277, 
+	277, 277, 288, 277, 358, 184, 359, 359, 
+	81, 187, 188, 189, 357, 357, 357, 191, 
+	357, 357, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 184, 359, 359, 81, 187, 188, 
+	189, 357, 357, 357, 191, 357, 357, 194, 
+	360, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 196, 357, 361, 
+	357, 357, 357, 95, 362, 357, 187, 188, 
+	189, 357, 357, 357, 363, 357, 361, 357, 
+	360, 357, 364, 365, 366, 367, 81, 187, 
+	188, 189, 357, 357, 112, 368, 357, 357, 
+	194, 360, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 196, 357, 
+	369, 365, 370, 370, 81, 187, 188, 189, 
+	357, 357, 357, 368, 357, 357, 194, 360, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 196, 357, 365, 370, 
+	370, 81, 187, 188, 189, 357, 357, 357, 
+	368, 357, 357, 194, 360, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 196, 357, 371, 357, 357, 357, 95, 
+	372, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 371, 357, 360, 357, 373, 374, 
+	375, 376, 81, 187, 188, 189, 357, 357, 
+	110, 377, 357, 357, 194, 360, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 196, 357, 378, 374, 379, 379, 
+	81, 187, 188, 189, 357, 357, 357, 377, 
+	357, 357, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 374, 379, 379, 81, 187, 188, 
+	189, 357, 357, 357, 377, 357, 357, 194, 
+	360, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 196, 357, 380, 
+	357, 357, 357, 95, 381, 357, 187, 188, 
+	189, 357, 357, 357, 363, 357, 380, 357, 
+	360, 357, 382, 383, 384, 385, 81, 187, 
+	188, 189, 357, 357, 108, 386, 357, 357, 
+	194, 360, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 196, 357, 
+	387, 383, 388, 388, 81, 187, 188, 189, 
+	357, 357, 357, 386, 357, 357, 194, 360, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 196, 357, 383, 388, 
+	388, 81, 187, 188, 189, 357, 357, 357, 
+	386, 357, 357, 194, 360, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 196, 357, 389, 357, 357, 357, 95, 
+	390, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 389, 357, 360, 357, 391, 392, 
+	393, 394, 81, 187, 188, 189, 357, 357, 
+	106, 395, 357, 357, 194, 360, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 196, 357, 396, 392, 397, 397, 
+	81, 187, 188, 189, 357, 357, 357, 395, 
+	357, 357, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 392, 397, 397, 81, 187, 188, 
+	189, 357, 357, 357, 395, 357, 357, 194, 
+	360, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 196, 357, 95, 
+	398, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 187, 188, 
+	189, 357, 357, 357, 363, 357, 357, 357, 
+	360, 357, 399, 357, 357, 400, 188, 189, 
+	357, 188, 189, 357, 188, 401, 357, 188, 
+	357, 399, 357, 357, 357, 188, 189, 357, 
+	402, 357, 403, 404, 357, 187, 188, 189, 
+	357, 357, 79, 357, 357, 357, 357, 360, 
+	357, 78, 357, 357, 357, 357, 187, 188, 
+	189, 357, 357, 357, 357, 357, 357, 357, 
+	360, 357, 187, 188, 189, 357, 357, 357, 
+	357, 357, 357, 357, 360, 357, 405, 357, 
+	357, 357, 357, 187, 188, 189, 357, 187, 
+	188, 189, 357, 402, 357, 357, 357, 357, 
+	187, 188, 189, 357, 357, 357, 357, 357, 
+	357, 357, 360, 357, 402, 357, 403, 357, 
+	357, 187, 188, 189, 357, 357, 79, 357, 
+	357, 357, 357, 360, 357, 95, 357, 406, 
+	406, 81, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 407, 104, 
+	408, 409, 85, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 104, 
+	408, 409, 85, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 408, 
+	408, 85, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 410, 101, 
+	411, 412, 88, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 101, 
+	411, 412, 88, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 411, 
+	411, 88, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 413, 98, 
+	414, 415, 91, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 98, 
+	414, 415, 91, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 414, 
+	414, 91, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 416, 95, 
+	357, 417, 357, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 95, 
+	357, 417, 357, 187, 188, 189, 357, 357, 
+	357, 363, 357, 357, 357, 360, 357, 418, 
+	357, 187, 188, 189, 357, 357, 357, 363, 
+	357, 357, 357, 360, 357, 95, 357, 357, 
+	357, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 357, 357, 360, 357, 77, 78, 
+	357, 357, 95, 398, 357, 187, 188, 189, 
+	357, 357, 357, 363, 357, 77, 357, 360, 
+	357, 392, 397, 397, 81, 187, 188, 189, 
+	357, 357, 357, 395, 357, 357, 357, 360, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 196, 357, 392, 397, 
+	397, 81, 187, 188, 189, 357, 357, 357, 
+	395, 357, 357, 357, 360, 357, 391, 392, 
+	397, 397, 81, 187, 188, 189, 357, 357, 
+	357, 395, 357, 357, 194, 360, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 196, 357, 391, 392, 393, 397, 
+	81, 187, 188, 189, 357, 357, 106, 395, 
+	357, 357, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 389, 357, 419, 357, 406, 406, 
+	81, 187, 188, 189, 357, 357, 357, 363, 
+	357, 389, 357, 360, 357, 389, 357, 357, 
+	357, 357, 357, 357, 187, 188, 189, 357, 
+	357, 357, 363, 357, 389, 357, 360, 357, 
+	389, 357, 357, 357, 357, 420, 357, 187, 
+	188, 189, 357, 357, 357, 363, 357, 389, 
+	357, 360, 357, 389, 357, 419, 357, 357, 
+	357, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 389, 357, 360, 357, 389, 78, 
+	357, 357, 95, 390, 357, 187, 188, 189, 
+	357, 357, 357, 363, 357, 389, 357, 360, 
+	357, 382, 383, 388, 388, 81, 187, 188, 
+	189, 357, 357, 357, 386, 357, 357, 194, 
+	360, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 196, 357, 382, 
+	383, 384, 388, 81, 187, 188, 189, 357, 
+	357, 108, 386, 357, 357, 194, 360, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 196, 357, 380, 357, 421, 
+	357, 406, 406, 81, 187, 188, 189, 357, 
+	357, 357, 363, 357, 380, 357, 360, 357, 
+	380, 357, 357, 357, 357, 357, 357, 187, 
+	188, 189, 357, 357, 357, 363, 357, 380, 
+	357, 360, 357, 380, 357, 357, 357, 357, 
+	422, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 380, 357, 360, 357, 380, 357, 
+	421, 357, 357, 357, 357, 187, 188, 189, 
+	357, 357, 357, 363, 357, 380, 357, 360, 
+	357, 380, 78, 357, 357, 95, 381, 357, 
+	187, 188, 189, 357, 357, 357, 363, 357, 
+	380, 357, 360, 357, 373, 374, 379, 379, 
+	81, 187, 188, 189, 357, 357, 357, 377, 
+	357, 357, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 373, 374, 375, 379, 81, 187, 
+	188, 189, 357, 357, 110, 377, 357, 357, 
+	194, 360, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 196, 357, 
+	371, 357, 423, 357, 406, 406, 81, 187, 
+	188, 189, 357, 357, 357, 363, 357, 371, 
+	357, 360, 357, 371, 357, 357, 357, 357, 
+	357, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 371, 357, 360, 357, 371, 357, 
+	357, 357, 357, 424, 357, 187, 188, 189, 
+	357, 357, 357, 363, 357, 371, 357, 360, 
+	357, 371, 357, 423, 357, 357, 357, 357, 
+	187, 188, 189, 357, 357, 357, 363, 357, 
+	371, 357, 360, 357, 371, 78, 357, 357, 
+	95, 372, 357, 187, 188, 189, 357, 357, 
+	357, 363, 357, 371, 357, 360, 357, 364, 
+	365, 370, 370, 81, 187, 188, 189, 357, 
+	357, 357, 368, 357, 357, 194, 360, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 357, 196, 357, 364, 365, 366, 
+	370, 81, 187, 188, 189, 357, 357, 112, 
+	368, 357, 357, 194, 360, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 196, 357, 361, 357, 425, 357, 406, 
+	406, 81, 187, 188, 189, 357, 357, 357, 
+	363, 357, 361, 357, 360, 357, 361, 357, 
+	357, 357, 357, 357, 357, 187, 188, 189, 
+	357, 357, 357, 363, 357, 361, 357, 360, 
+	357, 361, 357, 357, 357, 357, 426, 357, 
+	187, 188, 189, 357, 357, 357, 363, 357, 
+	361, 357, 360, 357, 361, 357, 425, 357, 
+	357, 357, 357, 187, 188, 189, 357, 357, 
+	357, 363, 357, 361, 357, 360, 357, 361, 
+	78, 357, 357, 95, 362, 357, 187, 188, 
+	189, 357, 357, 357, 363, 357, 361, 357, 
+	360, 357, 113, 80, 80, 81, 427, 427, 
+	427, 427, 427, 152, 113, 427, 183, 184, 
+	359, 359, 81, 187, 188, 189, 357, 357, 
+	357, 191, 357, 357, 194, 360, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	357, 357, 196, 357, 113, 80, 80, 81, 
+	427, 427, 427, 427, 427, 427, 113, 427, 
+	429, 430, 431, 432, 119, 433, 434, 435, 
+	428, 428, 151, 436, 428, 428, 437, 438, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 439, 428, 440, 430, 
+	432, 432, 119, 433, 434, 435, 428, 428, 
+	428, 436, 428, 428, 437, 438, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 439, 428, 430, 432, 432, 119, 
+	433, 434, 435, 428, 428, 428, 436, 428, 
+	428, 437, 438, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 439, 
+	428, 441, 428, 428, 428, 132, 442, 428, 
+	433, 434, 435, 428, 428, 428, 443, 428, 
+	441, 428, 438, 428, 444, 445, 446, 447, 
+	119, 433, 434, 435, 428, 428, 149, 448, 
+	428, 428, 437, 438, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	439, 428, 449, 445, 450, 450, 119, 433, 
+	434, 435, 428, 428, 428, 448, 428, 428, 
+	437, 438, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 439, 428, 
+	445, 450, 450, 119, 433, 434, 435, 428, 
+	428, 428, 448, 428, 428, 437, 438, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 439, 428, 451, 428, 428, 
+	428, 132, 452, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 451, 428, 438, 428, 
+	453, 454, 455, 456, 119, 433, 434, 435, 
+	428, 428, 147, 457, 428, 428, 437, 438, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 439, 428, 458, 454, 
+	459, 459, 119, 433, 434, 435, 428, 428, 
+	428, 457, 428, 428, 437, 438, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 439, 428, 454, 459, 459, 119, 
+	433, 434, 435, 428, 428, 428, 457, 428, 
+	428, 437, 438, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 439, 
+	428, 460, 428, 428, 428, 132, 461, 428, 
+	433, 434, 435, 428, 428, 428, 443, 428, 
+	460, 428, 438, 428, 462, 463, 464, 465, 
+	119, 433, 434, 435, 428, 428, 145, 466, 
+	428, 428, 437, 438, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	439, 428, 467, 463, 468, 468, 119, 433, 
+	434, 435, 428, 428, 428, 466, 428, 428, 
+	437, 438, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 439, 428, 
+	463, 468, 468, 119, 433, 434, 435, 428, 
+	428, 428, 466, 428, 428, 437, 438, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 439, 428, 469, 428, 428, 
+	428, 132, 470, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 469, 428, 438, 428, 
+	471, 472, 473, 474, 119, 433, 434, 435, 
+	428, 428, 143, 475, 428, 428, 437, 438, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 439, 428, 476, 472, 
+	477, 477, 119, 433, 434, 435, 428, 428, 
+	428, 475, 428, 428, 437, 438, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 439, 428, 472, 477, 477, 119, 
+	433, 434, 435, 428, 428, 428, 475, 428, 
+	428, 437, 438, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 439, 
+	428, 132, 478, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	433, 434, 435, 428, 428, 428, 443, 428, 
+	428, 428, 438, 428, 479, 428, 428, 480, 
+	434, 435, 428, 434, 435, 428, 434, 481, 
+	428, 434, 428, 479, 428, 428, 428, 434, 
+	435, 428, 482, 428, 483, 484, 428, 433, 
+	434, 435, 428, 428, 117, 428, 428, 428, 
+	428, 438, 428, 116, 428, 428, 428, 428, 
+	433, 434, 435, 428, 428, 428, 428, 428, 
+	428, 428, 438, 428, 433, 434, 435, 428, 
+	428, 428, 428, 428, 428, 428, 438, 428, 
+	485, 428, 428, 428, 428, 433, 434, 435, 
+	428, 433, 434, 435, 428, 482, 428, 428, 
+	428, 428, 433, 434, 435, 428, 428, 428, 
+	428, 428, 428, 428, 438, 428, 482, 428, 
+	483, 428, 428, 433, 434, 435, 428, 428, 
+	117, 428, 428, 428, 428, 438, 428, 132, 
+	428, 486, 486, 119, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	487, 141, 488, 489, 122, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 141, 488, 489, 122, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 488, 488, 122, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	490, 138, 491, 492, 125, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 138, 491, 492, 125, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 491, 491, 125, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	493, 135, 494, 495, 128, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 135, 494, 495, 128, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 494, 494, 128, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	496, 132, 428, 497, 428, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 132, 428, 497, 428, 433, 434, 435, 
+	428, 428, 428, 443, 428, 428, 428, 438, 
+	428, 498, 428, 433, 434, 435, 428, 428, 
+	428, 443, 428, 428, 428, 438, 428, 132, 
+	428, 428, 428, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 428, 428, 438, 428, 
+	115, 116, 428, 428, 132, 478, 428, 433, 
+	434, 435, 428, 428, 428, 443, 428, 115, 
+	428, 438, 428, 472, 477, 477, 119, 433, 
+	434, 435, 428, 428, 428, 475, 428, 428, 
+	428, 438, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 439, 428, 
+	472, 477, 477, 119, 433, 434, 435, 428, 
+	428, 428, 475, 428, 428, 428, 438, 428, 
+	471, 472, 477, 477, 119, 433, 434, 435, 
+	428, 428, 428, 475, 428, 428, 437, 438, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 439, 428, 471, 472, 
+	473, 477, 119, 433, 434, 435, 428, 428, 
+	143, 475, 428, 428, 437, 438, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 439, 428, 469, 428, 499, 428, 
+	486, 486, 119, 433, 434, 435, 428, 428, 
+	428, 443, 428, 469, 428, 438, 428, 469, 
+	428, 428, 428, 428, 428, 428, 433, 434, 
+	435, 428, 428, 428, 443, 428, 469, 428, 
+	438, 428, 469, 428, 428, 428, 428, 500, 
+	428, 433, 434, 435, 428, 428, 428, 443, 
+	428, 469, 428, 438, 428, 469, 428, 499, 
+	428, 428, 428, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 469, 428, 438, 428, 
+	469, 116, 428, 428, 132, 470, 428, 433, 
+	434, 435, 428, 428, 428, 443, 428, 469, 
+	428, 438, 428, 462, 463, 468, 468, 119, 
+	433, 434, 435, 428, 428, 428, 466, 428, 
+	428, 437, 438, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 439, 
+	428, 462, 463, 464, 468, 119, 433, 434, 
+	435, 428, 428, 145, 466, 428, 428, 437, 
+	438, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 439, 428, 460, 
+	428, 501, 428, 486, 486, 119, 433, 434, 
+	435, 428, 428, 428, 443, 428, 460, 428, 
+	438, 428, 460, 428, 428, 428, 428, 428, 
+	428, 433, 434, 435, 428, 428, 428, 443, 
+	428, 460, 428, 438, 428, 460, 428, 428, 
+	428, 428, 502, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 460, 428, 438, 428, 
+	460, 428, 501, 428, 428, 428, 428, 433, 
+	434, 435, 428, 428, 428, 443, 428, 460, 
+	428, 438, 428, 460, 116, 428, 428, 132, 
+	461, 428, 433, 434, 435, 428, 428, 428, 
+	443, 428, 460, 428, 438, 428, 453, 454, 
+	459, 459, 119, 433, 434, 435, 428, 428, 
+	428, 457, 428, 428, 437, 438, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 439, 428, 453, 454, 455, 459, 
+	119, 433, 434, 435, 428, 428, 147, 457, 
+	428, 428, 437, 438, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	439, 428, 451, 428, 503, 428, 486, 486, 
+	119, 433, 434, 435, 428, 428, 428, 443, 
+	428, 451, 428, 438, 428, 451, 428, 428, 
+	428, 428, 428, 428, 433, 434, 435, 428, 
+	428, 428, 443, 428, 451, 428, 438, 428, 
+	451, 428, 428, 428, 428, 504, 428, 433, 
+	434, 435, 428, 428, 428, 443, 428, 451, 
+	428, 438, 428, 451, 428, 503, 428, 428, 
+	428, 428, 433, 434, 435, 428, 428, 428, 
+	443, 428, 451, 428, 438, 428, 451, 116, 
+	428, 428, 132, 452, 428, 433, 434, 435, 
+	428, 428, 428, 443, 428, 451, 428, 438, 
+	428, 444, 445, 450, 450, 119, 433, 434, 
+	435, 428, 428, 428, 448, 428, 428, 437, 
+	438, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 439, 428, 444, 
+	445, 446, 450, 119, 433, 434, 435, 428, 
+	428, 149, 448, 428, 428, 437, 438, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	428, 428, 428, 439, 428, 441, 428, 505, 
+	428, 486, 486, 119, 433, 434, 435, 428, 
+	428, 428, 443, 428, 441, 428, 438, 428, 
+	441, 428, 428, 428, 428, 428, 428, 433, 
+	434, 435, 428, 428, 428, 443, 428, 441, 
+	428, 438, 428, 441, 428, 428, 428, 428, 
+	506, 428, 433, 434, 435, 428, 428, 428, 
+	443, 428, 441, 428, 438, 428, 441, 428, 
+	505, 428, 428, 428, 428, 433, 434, 435, 
+	428, 428, 428, 443, 428, 441, 428, 438, 
+	428, 441, 116, 428, 428, 132, 442, 428, 
+	433, 434, 435, 428, 428, 428, 443, 428, 
+	441, 428, 438, 428, 429, 430, 432, 432, 
+	119, 433, 434, 435, 428, 428, 428, 436, 
+	428, 428, 437, 438, 428, 428, 428, 428, 
+	428, 428, 428, 428, 428, 428, 428, 428, 
+	439, 428, 181, 182, 183, 184, 507, 359, 
+	81, 187, 188, 189, 190, 190, 152, 191, 
+	357, 181, 194, 360, 357, 357, 357, 357, 
+	357, 357, 357, 357, 357, 357, 357, 357, 
+	196, 357, 198, 508, 200, 201, 5, 202, 
+	203, 204, 197, 197, 37, 205, 197, 197, 
+	206, 207, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 208, 197, 
+	211, 182, 183, 184, 509, 510, 81, 511, 
+	203, 512, 190, 190, 152, 513, 197, 211, 
+	194, 514, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 196, 197, 
+	113, 80, 80, 81, 202, 203, 204, 197, 
+	197, 152, 515, 197, 197, 197, 207, 197, 
+	516, 2, 357, 357, 357, 426, 357, 187, 
+	188, 189, 357, 357, 357, 363, 357, 516, 
+	357, 360, 357, 517, 365, 518, 519, 81, 
+	511, 203, 512, 197, 197, 153, 368, 197, 
+	197, 194, 514, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 196, 
+	197, 520, 365, 370, 370, 81, 511, 203, 
+	512, 197, 197, 197, 368, 197, 197, 194, 
+	514, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 197, 197, 196, 197, 365, 
+	370, 370, 81, 511, 203, 512, 197, 197, 
+	197, 368, 197, 197, 194, 514, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 196, 197, 521, 197, 197, 522, 
+	203, 512, 197, 203, 512, 197, 203, 523, 
+	197, 203, 197, 521, 197, 197, 197, 203, 
+	512, 197, 524, 197, 197, 197, 197, 511, 
+	203, 512, 197, 511, 203, 512, 197, 517, 
+	365, 370, 370, 81, 511, 203, 512, 197, 
+	197, 197, 368, 197, 197, 194, 514, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 197, 197, 196, 197, 517, 365, 518, 
+	370, 81, 511, 203, 512, 197, 197, 153, 
+	368, 197, 197, 194, 514, 197, 197, 197, 
+	197, 197, 197, 197, 197, 197, 197, 197, 
+	197, 196, 197, 211, 197, 275, 113, 525, 
+	525, 155, 202, 203, 204, 197, 197, 197, 
+	515, 197, 211, 197, 207, 197, 526, 179, 
+	527, 528, 157, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 179, 
+	527, 528, 157, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 527, 
+	527, 157, 511, 203, 512, 197, 197, 197, 
+	529, 197, 197, 197, 514, 197, 530, 176, 
+	531, 532, 160, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 176, 
+	531, 532, 160, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 531, 
+	531, 160, 511, 203, 512, 197, 197, 197, 
+	529, 197, 197, 197, 514, 197, 533, 173, 
+	534, 535, 163, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 173, 
+	534, 535, 163, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 534, 
+	534, 163, 511, 203, 512, 197, 197, 197, 
+	529, 197, 197, 197, 514, 197, 536, 170, 
+	197, 537, 197, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 170, 
+	197, 537, 197, 511, 203, 512, 197, 197, 
+	197, 529, 197, 197, 197, 514, 197, 511, 
+	203, 512, 197, 197, 197, 529, 197, 197, 
+	197, 514, 197, 538, 197, 539, 540, 197, 
+	511, 203, 512, 197, 197, 167, 197, 197, 
+	197, 197, 514, 197, 166, 197, 197, 197, 
+	197, 511, 203, 512, 197, 197, 197, 197, 
+	197, 197, 197, 514, 197, 511, 203, 512, 
+	197, 197, 197, 197, 197, 197, 197, 514, 
+	197, 538, 197, 197, 197, 197, 511, 203, 
+	512, 197, 197, 197, 197, 197, 197, 197, 
+	514, 197, 538, 197, 539, 197, 197, 511, 
+	203, 512, 197, 197, 167, 197, 197, 197, 
+	197, 514, 197, 516, 166, 357, 357, 95, 
+	362, 357, 187, 188, 189, 357, 357, 357, 
+	363, 357, 516, 357, 360, 357, 542, 541, 
+	541, 541, 541, 543, 544, 545, 541, 543, 
+	544, 545, 541, 546, 541, 541, 547, 544, 
+	545, 541, 544, 545, 541, 544, 548, 541, 
+	544, 541, 546, 541, 541, 541, 544, 545, 
+	541, 0
 };
 
 static const short _indic_syllable_machine_trans_targs[] = {
-	170, 195, 197, 198, 3, 201, 4, 6, 
-	204, 7, 9, 207, 10, 12, 210, 13, 
-	15, 16, 191, 18, 19, 209, 21, 22, 
-	206, 24, 25, 203, 212, 216, 220, 223, 
-	227, 230, 234, 237, 241, 244, 170, 270, 
-	272, 273, 39, 276, 40, 42, 279, 43, 
-	45, 282, 46, 48, 285, 49, 51, 52, 
-	266, 54, 55, 284, 57, 58, 281, 60, 
-	61, 278, 287, 290, 294, 297, 301, 304, 
-	308, 311, 315, 319, 170, 343, 345, 346, 
-	75, 349, 170, 76, 78, 352, 79, 81, 
-	355, 82, 84, 358, 85, 87, 88, 339, 
-	90, 91, 357, 93, 94, 354, 96, 97, 
-	351, 360, 363, 367, 370, 374, 377, 381, 
-	384, 388, 170, 418, 420, 421, 110, 424, 
-	111, 113, 427, 114, 116, 430, 117, 119, 
-	433, 120, 122, 123, 414, 125, 126, 432, 
-	128, 129, 429, 131, 132, 426, 435, 438, 
-	442, 445, 449, 452, 456, 459, 463, 466, 
-	392, 478, 146, 481, 148, 484, 149, 151, 
-	487, 152, 154, 490, 155, 493, 495, 496, 
-	159, 160, 492, 162, 163, 489, 165, 166, 
-	486, 168, 169, 483, 170, 171, 246, 320, 
-	322, 391, 393, 340, 342, 394, 390, 467, 
-	468, 170, 172, 174, 35, 245, 192, 194, 
-	214, 243, 173, 34, 175, 239, 0, 176, 
-	178, 33, 238, 236, 177, 32, 179, 232, 
-	180, 182, 31, 231, 229, 181, 30, 183, 
-	225, 184, 186, 29, 224, 222, 185, 28, 
-	187, 218, 188, 190, 27, 217, 215, 189, 
-	26, 200, 193, 170, 196, 1, 199, 2, 
-	202, 5, 23, 205, 8, 20, 208, 11, 
-	17, 211, 14, 213, 219, 221, 226, 228, 
-	233, 235, 240, 242, 170, 247, 249, 71, 
-	317, 267, 269, 318, 248, 70, 250, 313, 
-	36, 251, 253, 69, 312, 310, 252, 68, 
-	254, 306, 255, 257, 67, 305, 303, 256, 
-	66, 258, 299, 259, 261, 65, 298, 296, 
-	260, 64, 262, 292, 263, 265, 63, 291, 
-	289, 264, 62, 275, 268, 170, 271, 37, 
-	274, 38, 277, 41, 59, 280, 44, 56, 
-	283, 47, 53, 286, 50, 288, 293, 295, 
-	300, 302, 307, 309, 314, 316, 170, 321, 
-	106, 323, 386, 72, 324, 326, 105, 385, 
-	383, 325, 104, 327, 379, 328, 330, 103, 
-	378, 376, 329, 102, 331, 372, 332, 334, 
-	101, 371, 369, 333, 100, 335, 365, 336, 
-	338, 99, 364, 362, 337, 98, 348, 341, 
-	170, 344, 73, 347, 74, 350, 77, 95, 
-	353, 80, 92, 356, 83, 89, 359, 86, 
-	361, 366, 368, 373, 375, 380, 382, 387, 
-	389, 170, 170, 395, 397, 142, 141, 415, 
-	417, 465, 396, 398, 461, 107, 399, 401, 
-	140, 460, 458, 400, 139, 402, 454, 403, 
-	405, 138, 453, 451, 404, 137, 406, 447, 
-	407, 409, 136, 446, 444, 408, 135, 410, 
-	440, 411, 413, 134, 439, 437, 412, 133, 
-	423, 416, 170, 419, 108, 422, 109, 425, 
-	112, 130, 428, 115, 127, 431, 118, 124, 
-	434, 121, 436, 441, 443, 448, 450, 455, 
-	457, 462, 464, 143, 469, 470, 480, 475, 
-	477, 498, 471, 472, 473, 144, 479, 474, 
-	476, 145, 482, 147, 167, 156, 485, 150, 
-	164, 488, 153, 161, 491, 158, 494, 157, 
-	497
+	170, 197, 199, 202, 3, 205, 4, 6, 
+	208, 7, 9, 211, 10, 12, 214, 13, 
+	15, 16, 191, 18, 19, 213, 21, 22, 
+	210, 24, 25, 207, 216, 221, 225, 228, 
+	232, 235, 239, 242, 246, 249, 170, 277, 
+	279, 282, 39, 285, 40, 42, 288, 43, 
+	45, 291, 46, 48, 294, 49, 51, 52, 
+	271, 54, 55, 293, 57, 58, 290, 60, 
+	61, 287, 296, 301, 305, 308, 312, 315, 
+	319, 322, 326, 330, 170, 356, 358, 361, 
+	75, 364, 170, 76, 78, 367, 79, 81, 
+	370, 82, 84, 373, 85, 87, 88, 350, 
+	90, 91, 372, 93, 94, 369, 96, 97, 
+	366, 375, 380, 384, 387, 391, 394, 398, 
+	401, 405, 170, 437, 439, 442, 110, 445, 
+	111, 113, 448, 114, 116, 451, 117, 119, 
+	454, 120, 122, 123, 431, 125, 126, 453, 
+	128, 129, 450, 131, 132, 447, 456, 461, 
+	465, 468, 472, 475, 479, 482, 486, 489, 
+	409, 505, 146, 508, 148, 511, 149, 151, 
+	514, 152, 154, 517, 155, 520, 522, 523, 
+	159, 160, 519, 162, 163, 516, 165, 166, 
+	513, 168, 169, 510, 170, 171, 251, 331, 
+	333, 408, 410, 351, 170, 353, 411, 407, 
+	490, 491, 378, 526, 379, 170, 172, 174, 
+	35, 250, 192, 170, 194, 248, 219, 200, 
+	220, 173, 34, 175, 244, 0, 176, 178, 
+	33, 243, 241, 177, 32, 179, 237, 180, 
+	182, 31, 236, 234, 181, 30, 183, 230, 
+	184, 186, 29, 229, 227, 185, 28, 187, 
+	223, 188, 190, 27, 222, 218, 189, 26, 
+	204, 193, 196, 195, 198, 1, 203, 201, 
+	2, 206, 5, 23, 209, 8, 20, 212, 
+	11, 17, 215, 14, 217, 224, 226, 231, 
+	233, 238, 240, 245, 247, 170, 252, 254, 
+	71, 328, 272, 170, 274, 329, 299, 280, 
+	300, 253, 70, 255, 324, 36, 256, 258, 
+	69, 323, 321, 257, 68, 259, 317, 260, 
+	262, 67, 316, 314, 261, 66, 263, 310, 
+	264, 266, 65, 309, 307, 265, 64, 267, 
+	303, 268, 270, 63, 302, 298, 269, 62, 
+	284, 273, 276, 275, 278, 37, 283, 281, 
+	38, 286, 41, 59, 289, 44, 56, 292, 
+	47, 53, 295, 50, 297, 304, 306, 311, 
+	313, 318, 320, 325, 327, 170, 332, 106, 
+	359, 334, 403, 72, 335, 337, 105, 402, 
+	400, 336, 104, 338, 396, 339, 341, 103, 
+	395, 393, 340, 102, 342, 389, 343, 345, 
+	101, 388, 386, 344, 100, 346, 382, 347, 
+	349, 99, 381, 377, 348, 98, 363, 352, 
+	355, 354, 357, 73, 362, 360, 74, 365, 
+	77, 95, 368, 80, 92, 371, 83, 89, 
+	374, 86, 376, 383, 385, 390, 392, 397, 
+	399, 404, 406, 170, 170, 412, 414, 142, 
+	141, 432, 170, 434, 488, 459, 440, 460, 
+	413, 415, 484, 107, 416, 418, 140, 483, 
+	481, 417, 139, 419, 477, 420, 422, 138, 
+	476, 474, 421, 137, 423, 470, 424, 426, 
+	136, 469, 467, 425, 135, 427, 463, 428, 
+	430, 134, 462, 458, 429, 133, 444, 433, 
+	436, 435, 438, 108, 443, 441, 109, 446, 
+	112, 130, 449, 115, 127, 452, 118, 124, 
+	455, 121, 457, 464, 466, 471, 473, 478, 
+	480, 485, 487, 143, 492, 493, 507, 498, 
+	500, 525, 503, 494, 495, 496, 144, 506, 
+	497, 499, 502, 501, 504, 145, 509, 147, 
+	167, 156, 512, 150, 164, 515, 153, 161, 
+	518, 158, 521, 157, 524, 170, 527, 528, 
+	170, 530, 529, 532, 531
 };
 
 static const char _indic_syllable_machine_trans_actions[] = {
 	1, 2, 0, 0, 0, 2, 0, 0, 
 	2, 0, 0, 2, 0, 0, 2, 0, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 0, 2, 2, 2, 2, 2, 
 	2, 2, 2, 2, 2, 2, 3, 2, 
@@ -991,58 +1348,62 @@ static const char _indic_syllable_machin
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 0, 0, 2, 0, 0, 2, 
 	0, 0, 2, 0, 0, 2, 2, 2, 
 	2, 2, 2, 2, 2, 2, 2, 2, 
 	6, 8, 0, 2, 0, 2, 0, 0, 
 	2, 0, 0, 2, 0, 2, 0, 0, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 0, 2, 11, 2, 2, 6, 
-	2, 12, 12, 0, 0, 2, 2, 6, 
-	2, 13, 2, 2, 0, 2, 0, 0, 
-	2, 2, 2, 0, 2, 2, 0, 2, 
+	2, 12, 12, 0, 13, 0, 2, 2, 
+	6, 2, 6, 0, 6, 14, 2, 2, 
+	0, 2, 0, 15, 0, 2, 2, 0, 
+	2, 2, 0, 2, 2, 0, 2, 2, 
+	0, 2, 2, 2, 0, 2, 2, 2, 
 	2, 0, 2, 2, 2, 0, 2, 2, 
 	2, 2, 0, 2, 2, 2, 0, 2, 
 	2, 2, 2, 0, 2, 2, 2, 0, 
-	2, 2, 2, 2, 0, 2, 2, 2, 
-	0, 2, 0, 14, 0, 0, 2, 0, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	0, 2, 0, 2, 2, 2, 2, 2, 
-	2, 2, 2, 2, 15, 2, 2, 0, 
-	2, 0, 0, 2, 2, 0, 2, 2, 
-	0, 2, 2, 0, 2, 2, 2, 0, 
-	2, 2, 2, 2, 0, 2, 2, 2, 
-	0, 2, 2, 2, 2, 0, 2, 2, 
-	2, 0, 2, 2, 2, 2, 0, 2, 
-	2, 2, 0, 2, 0, 16, 0, 0, 
-	2, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 2, 2, 2, 
-	2, 2, 2, 2, 2, 2, 17, 6, 
+	2, 0, 0, 0, 0, 0, 2, 0, 
+	0, 2, 0, 0, 2, 0, 0, 2, 
+	0, 0, 2, 0, 2, 2, 2, 2, 
+	2, 2, 2, 2, 2, 16, 2, 2, 
+	0, 2, 0, 17, 0, 2, 2, 0, 
+	2, 2, 0, 2, 2, 0, 2, 2, 
+	0, 2, 2, 2, 0, 2, 2, 2, 
+	2, 0, 2, 2, 2, 0, 2, 2, 
+	2, 2, 0, 2, 2, 2, 0, 2, 
+	2, 2, 2, 0, 2, 2, 2, 0, 
+	2, 0, 0, 0, 0, 0, 2, 0, 
+	0, 2, 0, 0, 2, 0, 0, 2, 
+	0, 0, 2, 0, 2, 2, 2, 2, 
+	2, 2, 2, 2, 2, 18, 6, 0, 
 	0, 6, 6, 0, 6, 2, 0, 6, 
 	2, 6, 0, 6, 6, 6, 2, 0, 
 	6, 2, 6, 0, 6, 6, 6, 2, 
 	0, 6, 2, 6, 0, 6, 6, 6, 
 	2, 0, 6, 2, 6, 0, 6, 0, 
-	18, 0, 0, 2, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 0, 2, 0, 
-	2, 2, 2, 2, 2, 2, 2, 2, 
-	2, 19, 20, 2, 2, 0, 0, 0, 
-	0, 2, 2, 2, 2, 0, 2, 2, 
+	0, 0, 0, 0, 2, 0, 0, 2, 
+	0, 0, 2, 0, 0, 2, 0, 0, 
+	2, 0, 2, 2, 2, 2, 2, 2, 
+	2, 2, 2, 19, 20, 2, 2, 0, 
+	0, 0, 21, 0, 2, 2, 0, 2, 
+	2, 2, 2, 0, 2, 2, 0, 2, 
+	2, 2, 0, 2, 2, 2, 2, 0, 
+	2, 2, 2, 0, 2, 2, 2, 2, 
 	0, 2, 2, 2, 0, 2, 2, 2, 
-	2, 0, 2, 2, 2, 0, 2, 2, 
-	2, 2, 0, 2, 2, 2, 0, 2, 
-	2, 2, 2, 0, 2, 2, 2, 0, 
-	2, 0, 21, 0, 0, 2, 0, 2, 
+	2, 0, 2, 2, 2, 0, 2, 0, 
+	0, 0, 0, 0, 2, 0, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 2, 2, 2, 2, 2, 2, 
 	2, 2, 2, 0, 0, 8, 2, 0, 
-	0, 2, 2, 8, 8, 0, 8, 8, 
-	0, 0, 2, 0, 0, 0, 2, 0, 
-	0, 2, 0, 0, 2, 0, 0, 0, 
-	2
+	0, 2, 0, 2, 8, 8, 0, 8, 
+	8, 0, 0, 0, 0, 0, 2, 0, 
+	0, 0, 2, 0, 0, 2, 0, 0, 
+	2, 0, 0, 0, 2, 22, 0, 0, 
+	23, 0, 0, 0, 0
 };
 
 static const char _indic_syllable_machine_to_state_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
@@ -1098,17 +1459,21 @@ static const char _indic_syllable_machin
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0
 };
 
 static const char _indic_syllable_machine_from_state_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
@@ -1164,17 +1529,21 @@ static const char _indic_syllable_machin
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0
 };
 
 static const short _indic_syllable_machine_eof_trans[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 39, 39, 39, 39, 
@@ -1189,72 +1558,76 @@ static const short _indic_syllable_machi
 	83, 77, 77, 115, 115, 115, 115, 115, 
 	115, 115, 115, 115, 115, 115, 115, 115, 
 	115, 115, 115, 115, 115, 115, 115, 115, 
 	115, 115, 115, 115, 115, 115, 115, 115, 
 	115, 115, 115, 115, 115, 115, 115, 77, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 0, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	269, 269, 269, 269, 269, 269, 269, 269, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 343, 
-	343, 343, 343, 343, 343, 343, 343, 410, 
-	343, 410, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 411, 411, 411, 411, 411, 
-	411, 411, 411, 343, 194, 194, 194, 343, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 194, 194, 194, 194, 194, 194, 
-	194, 194, 343
+	1, 1, 0, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 278, 278, 278, 278, 278, 
+	278, 278, 278, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	358, 358, 358, 358, 358, 358, 358, 358, 
+	428, 358, 428, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 429, 429, 429, 429, 429, 429, 
+	429, 429, 358, 198, 198, 198, 358, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 198, 198, 198, 
+	198, 198, 198, 198, 198, 358, 542, 542, 
+	542, 542, 542, 542, 542
 };
 
 static const int indic_syllable_machine_start = 170;
 static const int indic_syllable_machine_first_final = 170;
 static const int indic_syllable_machine_error = -1;
 
 static const int indic_syllable_machine_en_main = 170;
 
 
 #line 36 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
 
-#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 98 "../../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; \
@@ -1264,48 +1637,48 @@ static const int indic_syllable_machine_
 
 static void
 find_syllables (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 1273 "hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1646 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
 	te = 0;
 	act = 0;
 	}
 
-#line 112 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 119 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
   pe = eof = buffer->len;
 
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 1290 "hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1663 "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 10:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 1304 "hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1677 "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] ?
@@ -1317,127 +1690,135 @@ find_syllables (hb_buffer_t *buffer)
 	if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
 		goto _again;
 
 	switch ( _indic_syllable_machine_trans_actions[_trans] ) {
 	case 2:
 #line 1 "NONE"
 	{te = p+1;}
 	break;
-	case 14:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 15:
+#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (consonant_syllable); }}
 	break;
-	case 16:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 17:
+#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (vowel_syllable); }}
 	break;
 	case 21:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (standalone_cluster); }}
 	break;
-	case 18:
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 23:
+#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{te = p+1;{ found_syllable (avagraha_cluster); }}
+	break;
+	case 13:
+#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (broken_cluster); }}
 	break;
 	case 11:
-#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 94 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p+1;{ found_syllable (non_indic_cluster); }}
 	break;
-	case 13:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 14:
+#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (consonant_syllable); }}
 	break;
-	case 15:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 16:
+#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (vowel_syllable); }}
 	break;
 	case 20:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (standalone_cluster); }}
 	break;
-	case 17:
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	case 22:
+#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{te = p;p--;{ found_syllable (avagraha_cluster); }}
+	break;
+	case 18:
+#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (broken_cluster); }}
 	break;
 	case 19:
-#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 94 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{te = p;p--;{ found_syllable (non_indic_cluster); }}
 	break;
 	case 1:
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
 	break;
 	case 3:
-#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
 	break;
 	case 7:
-#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
 	break;
 	case 4:
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
 	break;
 	case 5:
 #line 1 "NONE"
 	{	switch( act ) {
 	case 1:
 	{{p = ((te))-1;} found_syllable (consonant_syllable); }
 	break;
-	case 4:
+	case 5:
 	{{p = ((te))-1;} found_syllable (broken_cluster); }
 	break;
-	case 5:
+	case 6:
 	{{p = ((te))-1;} found_syllable (non_indic_cluster); }
 	break;
 	}
 	}
 	break;
 	case 8:
 #line 1 "NONE"
 	{te = p+1;}
-#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{act = 1;}
 	break;
 	case 6:
 #line 1 "NONE"
 	{te = p+1;}
-#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl"
-	{act = 4;}
+#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{act = 5;}
 	break;
 	case 12:
 #line 1 "NONE"
 	{te = p+1;}
-#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
-	{act = 5;}
+#line 94 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{act = 6;}
 	break;
-#line 1415 "hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1796 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 _again:
 	switch ( _indic_syllable_machine_to_state_actions[cs] ) {
 	case 9:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 1424 "hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1805 "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 121 "../../src/hb-ot-shape-complex-indic-machine.rl"
+#line 128 "../../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
@@ -46,48 +46,55 @@ H    = 4;
 ZWNJ = 5;
 ZWJ  = 6;
 M    = 7;
 SM   = 8;
 VD   = 9;
 A    = 10;
 NBSP = 11;
 DOTTEDCIRCLE = 12;
-RS   = 13;
+RS    = 13;
 Coeng = 14;
 Repha = 15;
 Ra    = 16;
 CM    = 17;
+Avag  = 18;
+CM2   = 31;
 
-c = (C | Ra)CM*;		# is_consonant
+c = (C | Ra);			# 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;
+avagraha = Avag.N?;
 matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
-syllable_tail =  (Coeng (cn|V))? (SM.ZWNJ?)? (VD VD?)?;
+syllable_tail2 = (SM.SM?.ZWNJ?)? (A.A?)? VD?;
+syllable_tail =  (Coeng (cn|V))? avagraha? syllable_tail2;
 place_holder = NBSP | DOTTEDCIRCLE;
 halant_group = (z?.h.(ZWJ.N?)?);
 final_halant_group = halant_group | h.ZWNJ;
+medial_group = CM?.CM2?;
 halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4});
 
 
-consonant_syllable =	Repha? (cn.halant_group){0,4} cn A? halant_or_matra_group? syllable_tail;
-vowel_syllable =	reph? V.n? (ZWJ | (halant_group.cn){0,4} halant_or_matra_group? syllable_tail);
-standalone_cluster =	reph? place_holder.n? (halant_group.cn){0,4} halant_or_matra_group? syllable_tail;
-broken_cluster =	reph? n? (halant_group.cn){0,4} halant_or_matra_group syllable_tail;
+consonant_syllable =	Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
+vowel_syllable =	reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail);
+standalone_cluster =	reph? place_holder.n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+avagraha_cluster = 	avagraha syllable_tail2;
+broken_cluster =	reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
 other =			any;
 
 main := |*
 	consonant_syllable	=> { found_syllable (consonant_syllable); };
 	vowel_syllable		=> { found_syllable (vowel_syllable); };
 	standalone_cluster	=> { found_syllable (standalone_cluster); };
+	avagraha_cluster	=> { found_syllable (avagraha_cluster); };
 	broken_cluster		=> { found_syllable (broken_cluster); };
 	other			=> { found_syllable (non_indic_cluster); };
 *|;
 
 
 }%%
 
 #define found_syllable(syllable_type) \
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
@@ -38,33 +38,35 @@
 
 /* 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,
-  OT_C,
-  OT_V,
-  OT_N,
-  OT_H,
-  OT_ZWNJ,
-  OT_ZWJ,
-  OT_M,
-  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_CM
+  OT_C = 1,
+  OT_V = 2,
+  OT_N = 3,
+  OT_H = 4,
+  OT_ZWNJ = 5,
+  OT_ZWJ = 6,
+  OT_M = 7,
+  OT_SM = 8,
+  OT_VD = 9,
+  OT_A = 10,
+  OT_NBSP = 11,
+  OT_DOTTEDCIRCLE = 12,
+  OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
+  OT_Coeng = 14, /* Khmer-style Virama. */
+  OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
+  OT_Ra = 16,
+  OT_CM = 17,  /* Consonant-Medial. */
+  OT_Avag = 18, /* Avagraha. */
+  OT_CM2 = 31 /* Consonant-Medial, second slot. */
 };
 
 /* Visual positions in a syllable from left to right. */
 enum indic_position_t {
   POS_START,
 
   POS_RA_TO_BECOME_REPH,
   POS_PRE_M,
@@ -88,25 +90,25 @@ enum indic_position_t {
 
   POS_END
 };
 
 /* Categories used in IndicSyllabicCategory.txt from UCD. */
 enum indic_syllabic_category_t {
   INDIC_SYLLABIC_CATEGORY_OTHER			= OT_X,
 
-  INDIC_SYLLABIC_CATEGORY_AVAGRAHA		= OT_X,
+  INDIC_SYLLABIC_CATEGORY_AVAGRAHA		= OT_Avag,
   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_CM,
   INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	= 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_SUBJOINED	= OT_CM,
   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_N,
   INDIC_SYLLABIC_CATEGORY_VIRAMA		= OT_H,
   INDIC_SYLLABIC_CATEGORY_VISARGA		= OT_SM,
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -123,54 +123,48 @@ static const hb_codepoint_t ra_chars[] =
   0x0CB0, /* Kannada */
   0x0D30, /* Malayalam */	/* No Reph, Logical Repha */
 
   0x0DBB, /* Sinhala */		/* Reph formed only with ZWJ */
 
   0x179A, /* Khmer */		/* No Reph, Visual Repha */
 };
 
-static inline indic_position_t
-consonant_position (hb_codepoint_t  u)
-{
-  if ((u & ~0x007F) == 0x1780)
-    return POS_BELOW_C; /* In Khmer coeng model, post and below forms should not be reordered. */
-  return POS_BASE_C; /* Will recategorize later based on font lookups. */
-}
-
 static inline bool
 is_ra (hb_codepoint_t u)
 {
   for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
     if (u == ra_chars[i])
       return true;
   return false;
 }
 
 static inline bool
 is_one_of (const hb_glyph_info_t &info, unsigned int flags)
 {
   /* If it ligated, all bets are off. */
-  if (is_a_ligature (info)) return false;
+  if (_hb_glyph_info_ligated (&info)) return false;
   return !!(FLAG (info.indic_category()) & flags);
 }
 
 #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
 static inline bool
 is_joiner (const hb_glyph_info_t &info)
 {
   return is_one_of (info, JOINER_FLAGS);
 }
 
+#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
+
 /* 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_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | 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
@@ -189,25 +183,25 @@ set_indic_properties (hb_glyph_info_t &i
 
 
   /*
    * Re-assign category
    */
 
 
   /* The spec says U+0952 is OT_A.  However, testing shows that Uniscribe
-   * treats U+0951..U+0952 all as OT_VD.
+   * treats U+0951..U+0954 all behave similarly.
    * TESTS:
    * U+092E,U+0947,U+0952
    * U+092E,U+0952,U+0947
    * U+092E,U+0947,U+0951
    * U+092E,U+0951,U+0947
-   * */
+   */
   if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0951, 0x0954)))
-    cat = OT_VD;
+    cat = OT_A;
 
   if (unlikely (u == 0x17D1))
     cat = OT_X;
   if (cat == OT_X &&
       unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CB, 0x17D3))) /* Khmer Various signs */
   {
     /* These are like Top Matras. */
     cat = OT_M;
@@ -215,17 +209,20 @@ set_indic_properties (hb_glyph_info_t &i
   }
   if (u == 0x17C6) /* Khmer Bindu doesn't like to be repositioned. */
     cat = OT_N;
 
   if (unlikely (u == 0x17D2)) cat = OT_Coeng; /* Khmer coeng */
   else if (unlikely (u == 0x200C)) cat = OT_ZWNJ;
   else if (unlikely (u == 0x200D)) cat = OT_ZWJ;
   else if (unlikely (u == 0x25CC)) cat = OT_DOTTEDCIRCLE;
-  else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK.  More like consonant medial. like 0A75. */
+  else if (unlikely (u == 0x0A71)) cat = OT_SM; /* GURMUKHI ADDAK.  Move it to the end. */
+  else if (unlikely (u == 0xA982)) cat = OT_SM; /* Javanese repha. */
+  else if (unlikely (u == 0xA9BE)) cat = OT_CM2; /* Javanese medial ya. */
+  else if (unlikely (u == 0xA9BD)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
 
   if (cat == OT_Repha) {
     /* There are two kinds of characters marked as Repha:
      * - The ones that are GenCat=Mn are already positioned visually, ie. after base. (eg. Khmer)
      * - The ones that are GenCat=Lo is encoded logically, ie. beginning of syllable. (eg. Malayalam)
      *
      * We recategorize the first kind to look like a Nukta and attached to the base directly.
      */
@@ -236,25 +233,25 @@ set_indic_properties (hb_glyph_info_t &i
 
 
   /*
    * Re-assign position.
    */
 
   if ((FLAG (cat) & CONSONANT_FLAGS))
   {
-    pos = consonant_position (u);
+    pos = POS_BASE_C;
     if (is_ra (u))
       cat = OT_Ra;
   }
   else if (cat == OT_M)
   {
     pos = matra_position (u, pos);
   }
-  else if (cat == OT_SM || cat == OT_VD)
+  else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Avag))))
   {
     pos = POS_SMVD;
   }
 
   if (unlikely (u == 0x0B01)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
 
 
 
@@ -272,59 +269,71 @@ set_indic_properties (hb_glyph_info_t &i
  * behavior in these tables necessarily.  This should mainly be used for per-script
  * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
  * only one script has an exception, that one script can be if'ed directly in the code,
  * instead of adding a new flag in these structs.
  */
 
 enum base_position_t {
   BASE_POS_FIRST,
+  BASE_POS_LAST_SINHALA,
   BASE_POS_LAST
 };
 enum reph_position_t {
-  REPH_POS_DEFAULT     = POS_BEFORE_POST,
-
   REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
   REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
   REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
   REPH_POS_BEFORE_POST = POS_BEFORE_POST,
-  REPH_POS_AFTER_POST  = POS_AFTER_POST
+  REPH_POS_AFTER_POST  = POS_AFTER_POST,
+  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH
 };
 enum reph_mode_t {
   REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
   REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
   REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
   REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
 };
+enum blwf_mode_t {
+  BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
+  BLWF_MODE_POST_ONLY     /* Below-forms feature applied to post-base only. */
+};
+enum pref_len_t {
+  PREF_LEN_1 = 1,
+  PREF_LEN_2 = 2,
+  PREF_LEN_DONT_CARE = PREF_LEN_2
+};
 struct indic_config_t
 {
   hb_script_t     script;
   bool            has_old_spec;
   hb_codepoint_t  virama;
   base_position_t base_pos;
   reph_position_t reph_pos;
   reph_mode_t     reph_mode;
+  blwf_mode_t     blwf_mode;
+  pref_len_t      pref_len;
 };
 
 static const indic_config_t indic_configs[] =
 {
   /* Default.  Should be first. */
-  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT},
-  {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
-  {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT},
-  {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT},
-  {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},
-  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT},
+  {HB_SCRIPT_INVALID,	false,     0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_BENGALI,	true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GURMUKHI,	true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_LAST_SINHALA,
+						    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
 };
 
 
 
 /*
  * Indic shaper.
  */
 
@@ -341,25 +350,27 @@ indic_features[] =
    * These features are applied in order, one at a time, after initial_reordering.
    */
   {HB_TAG('n','u','k','t'), F_GLOBAL},
   {HB_TAG('a','k','h','n'), F_GLOBAL},
   {HB_TAG('r','p','h','f'), F_NONE},
   {HB_TAG('r','k','r','f'), F_GLOBAL},
   {HB_TAG('p','r','e','f'), F_NONE},
   {HB_TAG('b','l','w','f'), F_NONE},
+  {HB_TAG('a','b','v','f'), F_NONE},
   {HB_TAG('h','a','l','f'), F_NONE},
-  {HB_TAG('a','b','v','f'), F_NONE},
   {HB_TAG('p','s','t','f'), F_NONE},
-  {HB_TAG('c','f','a','r'), F_NONE},
   {HB_TAG('v','a','t','u'), F_GLOBAL},
   {HB_TAG('c','j','c','t'), F_GLOBAL},
+  {HB_TAG('c','f','a','r'), F_NONE},
   /*
    * Other features.
    * These features are applied all at once, after final_reordering.
+   * Default Bengali font in Windows for example has intermixed
+   * lookups for init,pres,abvs,blws features.
    */
   {HB_TAG('i','n','i','t'), F_NONE},
   {HB_TAG('p','r','e','s'), F_GLOBAL},
   {HB_TAG('a','b','v','s'), F_GLOBAL},
   {HB_TAG('b','l','w','s'), F_GLOBAL},
   {HB_TAG('p','s','t','s'), F_GLOBAL},
   {HB_TAG('h','a','l','n'), F_GLOBAL},
   /* Positioning features, though we don't care about the types. */
@@ -373,22 +384,22 @@ indic_features[] =
  */
 enum {
   _NUKT,
   _AKHN,
   RPHF,
   _RKRF,
   PREF,
   BLWF,
+  ABVF,
   HALF,
-  ABVF,
   PSTF,
-  CFAR,
   _VATU,
   _CJCT,
+  CFAR,
 
   INIT,
   _PRES,
   _ABVS,
   _BLWS,
   _PSTS,
   _HALN,
   _DIST,
@@ -406,16 +417,20 @@ setup_syllables (const hb_ot_shape_plan_
 static void
 initial_reordering (const hb_ot_shape_plan_t *plan,
 		    hb_font_t *font,
 		    hb_buffer_t *buffer);
 static void
 final_reordering (const hb_ot_shape_plan_t *plan,
 		  hb_font_t *font,
 		  hb_buffer_t *buffer);
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan,
+		 hb_font_t *font,
+		 hb_buffer_t *buffer);
 
 static void
 collect_features_indic (hb_ot_shape_planner_t *plan)
 {
   hb_ot_map_builder_t *map = &plan->map;
 
   /* Do this before any lookups have been applied. */
   map->add_gsub_pause (setup_syllables);
@@ -431,56 +446,65 @@ collect_features_indic (hb_ot_shape_plan
   for (; i < INDIC_BASIC_FEATURES; i++) {
     map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
     map->add_gsub_pause (NULL);
   }
   map->add_gsub_pause (final_reordering);
   for (; i < INDIC_NUM_FEATURES; i++) {
     map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
   }
+
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+
+  map->add_gsub_pause (clear_syllables);
 }
 
 static void
 override_features_indic (hb_ot_shape_planner_t *plan)
 {
-  /* Uniscribe does not apply 'kern'. */
+  /* Uniscribe does not apply 'kern' in Khmer. */
   if (hb_options ().uniscribe_bug_compatible)
-    plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
-
-  /* 'calt' is enabled by default in hb-ot-shape.cc, but is a discretionary,
-     non-default feature for Indic scripts. */
-  plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
+  {
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_KHMER:
+	plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+	break;
+    }
+  }
 
   plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 }
 
 
 struct would_substitute_feature_t
 {
-  inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
+  inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
   {
+    zero_context = zero_context_;
     map->get_stage_lookups (0/*GSUB*/,
 			    map->get_feature_stage (0/*GSUB*/, feature_tag),
 			    &lookups, &count);
   }
 
   inline bool would_substitute (const 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_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;
+  bool zero_context;
 };
 
 struct indic_shape_plan_t
 {
   ASSERT_POD ();
 
   inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
   {
@@ -526,68 +550,76 @@ data_create_indic (const hb_ot_shape_pla
     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.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'));
+  /* Use zero-context would_substitute() matching for new-spec of the main
+   * Indic scripts, but not for old-spec or scripts with one spec only. */
+  bool zero_context = indic_plan->config->has_old_spec || !indic_plan->is_old_spec;
+  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+  indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
     indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
 				 0 : plan->map.get_1_mask (indic_features[i].tag);
 
   return indic_plan;
 }
 
 static void
 data_destroy_indic (void *data)
 {
   free (data);
 }
 
 static indic_position_t
 consonant_position_from_face (const indic_shape_plan_t *indic_plan,
-			      const hb_codepoint_t glyphs[2],
+			      const hb_codepoint_t consonant,
+			      const hb_codepoint_t virama,
 			      hb_face_t *face)
 {
   /* For old-spec, the order of glyphs is Consonant,Virama,
    * whereas for new-spec, it's Virama,Consonant.  However,
    * some broken fonts (like Free Sans) simply copied lookups
    * from old-spec to new-spec without modification.
    * And oddly enough, Uniscribe seems to respect those lookups.
    * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
    * base at 0.  The font however, only has lookups matching
    * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
    * table).  As such, we simply match both sequences.  Seems
    * to work. */
-  bool zero_context = indic_plan->is_old_spec ? false : true;
-  hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]};
-  if (indic_plan->pref.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face))
+  hb_codepoint_t glyphs[3] = {virama, consonant, virama};
+  if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+    return POS_BELOW_C;
+  if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pstf.would_substitute (glyphs+1, 2, face))
     return POS_POST_C;
-  if (indic_plan->blwf.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face))
-    return POS_BELOW_C;
-  if (indic_plan->pstf.would_substitute (glyphs  , 2, zero_context, face) ||
-      indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face))
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if ((pref_len == PREF_LEN_2 &&
+       (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
+        indic_plan->pref.would_substitute (glyphs+1, 2, face)))
+   || (pref_len == PREF_LEN_1 &&
+       indic_plan->pref.would_substitute (glyphs+1, 1, face)))
     return POS_POST_C;
   return POS_BASE_C;
 }
 
 
 enum syllable_type_t {
   consonant_syllable,
   vowel_syllable,
   standalone_cluster,
+  avagraha_cluster,
   broken_cluster,
   non_indic_cluster,
 };
 
 #include "hb-ot-shape-complex-indic-machine.hh"
 
 
 static void
@@ -627,25 +659,28 @@ compare_indic_order (const hb_glyph_info
 
 static void
 update_consonant_positions (const hb_ot_shape_plan_t *plan,
 			    hb_font_t         *font,
 			    hb_buffer_t       *buffer)
 {
   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
 
-  hb_codepoint_t glyphs[2];
-  if (indic_plan->get_virama_glyph (font, &glyphs[0]))
+  if (indic_plan->config->base_pos != BASE_POS_LAST)
+    return;
+
+  hb_codepoint_t virama;
+  if (indic_plan->get_virama_glyph (font, &virama))
   {
     hb_face_t *face = font->face;
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++)
       if (buffer->info[i].indic_position() == POS_BASE_C) {
-	glyphs[1] = buffer->info[i].codepoint;
-	buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, face);
+	hb_codepoint_t consonant = buffer->info[i].codepoint;
+	buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
       }
   }
 }
 
 
 /* Rules from:
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
 
@@ -676,26 +711,27 @@ initial_reordering_consonant_syllable (c
   unsigned int base = end;
   bool has_reph = false;
 
   {
     /* -> 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] &&
+    if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
+	indic_plan->mask_array[RPHF] &&
 	start + 3 <= end &&
 	(
 	 (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)
 	))
     {
       /* 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))
+      if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), face))
       {
 	limit += 2;
 	while (limit < end && is_joiner (info[limit]))
 	  limit++;
 	base = start;
 	has_reph = true;
       }
     } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
@@ -757,37 +793,56 @@ initial_reordering_consonant_syllable (c
 		info[i].indic_category() == OT_ZWJ &&
 		info[i - 1].indic_category() == OT_H)
 	      break;
 	  }
 	} while (i > limit);
       }
       break;
 
-      case BASE_POS_FIRST:
+      case BASE_POS_LAST_SINHALA:
       {
-	/* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
+        /* Sinhala base positioning is slightly different from main Indic, in that:
+	 * 1. It's ZWJ behavior is different,
+	 * 2. We don't need to look into the font for consonant positions.
+	 */
 
 	if (!has_reph)
 	  base = limit;
 
 	/* Find the last base consonant that is not blocked by ZWJ.  If there is
 	 * a ZWJ right before a base consonant, that would request a subjoined form. */
 	for (unsigned int i = limit; i < end; i++)
-	  if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
+	  if (is_consonant (info[i]))
 	  {
 	    if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
 	      break;
 	    else
 	      base = i;
 	  }
 
 	/* 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)
+	  if (is_consonant (info[i]))
+	    info[i].indic_position() = POS_BELOW_C;
+      }
+      break;
+
+      case BASE_POS_FIRST:
+      {
+	/* The first consonant is always the base. */
+
+	assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+	assert (!has_reph);
+
+	base = start;
+
+	/* 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_BELOW_C;
       }
       break;
     }
 
     /* -> 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.
@@ -876,17 +931,17 @@ 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)))
+      if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
       {
 	info[i].indic_position() = last_pos;
 	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
@@ -902,56 +957,94 @@ initial_reordering_consonant_syllable (c
 	      break;
 	    }
 	}
       } else if (info[i].indic_position() != POS_SMVD) {
         last_pos = (indic_position_t) info[i].indic_position();
       }
     }
   }
-  /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */
+  /* For post-base consonants let them own anything before them
+   * since the last consonant or matra. */
   {
-    unsigned int last_halant = end;
+    unsigned int last = base;
     for (unsigned int i = base + 1; i < end; i++)
-      if (is_halant_or_coeng (info[i]))
-        last_halant = i;
-      else if (is_consonant (info[i])) {
-	for (unsigned int j = last_halant; j < i; j++)
-	  if (info[j].indic_position() != POS_SMVD)
+      if (is_consonant (info[i]))
+      {
+	for (unsigned int j = last + 1; j < i; j++)
+	  if (info[j].indic_position() < POS_SMVD)
 	    info[j].indic_position() = info[i].indic_position();
-      }
+	last = i;
+      } else if (info[i].indic_category() == OT_M)
+        last = i;
   }
 
+
   {
-    /* Things are out-of-control for post base positions, they may shuffle
-     * around like crazy, so merge clusters.  For pre-base stuff, we handle
-     * cluster issues in final reordering. */
-    buffer->merge_clusters (base, end);
+    /* Use syllable() for sort accounting temporarily. */
+    unsigned int syllable = info[start].syllable();
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = i - start;
+
     /* Sit tight, rock 'n roll! */
     hb_bubble_sort (info + start, end - start, compare_indic_order);
     /* Find base again */
     base = end;
     for (unsigned int i = start; i < end; i++)
-      if (info[i].indic_position() == POS_BASE_C) {
-        base = i;
+      if (info[i].indic_position() == POS_BASE_C)
+      {
+	base = i;
 	break;
       }
+    /* Things are out-of-control for post base positions, they may shuffle
+     * around like crazy.  In old-spec mode, we move halants around, so in
+     * that case merge all clusters after base.  Otherwise, check the sort
+     * order and merge as needed.
+     * For pre-base stuff, we handle cluster issues in final reordering. */
+    if (indic_plan->is_old_spec || end - base > 127)
+      buffer->merge_clusters (base, end);
+    else
+    {
+      /* Note!  syllable() is a one-byte field. */
+      for (unsigned int i = base; i < end; i++)
+        if (info[i].syllable() != 255)
+	{
+	  unsigned int max = i;
+	  unsigned int j = start + info[i].syllable();
+	  while (j != i)
+	  {
+	    max = MAX (max, j);
+	    unsigned int next = start + info[j].syllable();
+	    info[j].syllable() = 255; /* So we don't process j later again. */
+	    j = next;
+	  }
+	  if (i != max)
+	    buffer->merge_clusters (i, max + 1);
+	}
+    }
+
+    /* Put syllable back in. */
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = syllable;
   }
 
   /* Setup masks now */
 
   {
     hb_mask_t mask;
 
     /* Reph */
     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
       info[i].mask |= indic_plan->mask_array[RPHF];
 
     /* Pre-base */
     mask = indic_plan->mask_array[HALF];
+    if (!indic_plan->is_old_spec &&
+	indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
+      mask |= indic_plan->mask_array[BLWF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;
     /* Base */
     mask = 0;
     if (base < end)
       info[base].mask |= mask;
     /* Post-base */
     mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
@@ -986,34 +1079,39 @@ initial_reordering_consonant_syllable (c
 	  (i + 2 == base ||
 	   info[i+2].indic_category() != OT_ZWJ))
       {
 	info[i  ].mask |= indic_plan->mask_array[BLWF];
 	info[i+1].mask |= indic_plan->mask_array[BLWF];
       }
   }
 
-  if (indic_plan->mask_array[PREF] && base + 2 < end)
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if (indic_plan->mask_array[PREF] && base + pref_len < end)
   {
+    assert (1 <= pref_len && pref_len <= 2);
     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
-    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))
+    for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
+      hb_codepoint_t glyphs[2];
+      for (unsigned int j = 0; j < pref_len; j++)
+        glyphs[j] = info[i + j].codepoint;
+      if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
       {
-	info[i++].mask |= indic_plan->mask_array[PREF];
-	info[i++].mask |= indic_plan->mask_array[PREF];
+	for (unsigned int j = 0; j < pref_len; j++)
+	  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];
+	if (indic_plan->mask_array[CFAR])
+	  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++)
@@ -1074,16 +1172,26 @@ initial_reordering_broken_cluster (const
 				   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, face, buffer, start, end);
 }
 
 static void
+initial_reordering_avagraha_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_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. */
 }
@@ -1095,16 +1203,17 @@ initial_reordering_syllable (const hb_ot
 			     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, 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 avagraha_cluster:	initial_reordering_avagraha_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_UNUSED,
 		       hb_font_t *font,
@@ -1264,19 +1373,19 @@ final_reordering_syllable (const hb_ot_s
 	if (info[i - 1].indic_position () == POS_PRE_M)
 	{
 	  unsigned int old_pos = i - 1;
 	  hb_glyph_info_t tmp = info[old_pos];
 	  memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
 	  info[new_pos] = tmp;
 	  if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
 	    base--;
+	  buffer->merge_clusters (new_pos, MIN (end, base + 1));
 	  new_pos--;
 	}
-      buffer->merge_clusters (new_pos, MIN (end, base + 1));
     } else {
       for (unsigned int i = start; i < base; i++)
 	if (info[i].indic_position () == POS_PRE_M) {
 	  buffer->merge_clusters (i, MIN (end, base + 1));
 	  break;
 	}
     }
   }
@@ -1286,27 +1395,34 @@ final_reordering_syllable (const hb_ot_s
    *
    *     Reph’s original position is always at the beginning of the syllable,
    *     (i.e. it is not reordered at the character reordering stage). However,
    *     it will be reordered according to the basic-forms shaping results.
    *     Possible positions for reph, depending on the script, are; after main,
    *     before post-base consonant forms, and after post-base consonant forms.
    */
 
-  /* If there's anything after the Ra that has the REPH pos, it ought to be halant.
-   * Which means that the font has failed to ligate the Reph.  In which case, we
-   * shouldn't move. */
+  /* Two cases:
+   *
+   * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
+   *   we should only move it if the sequence ligated to the repha form.
+   *
+   * - If repha is encoded separately and in the logical position, we should only
+   *   move it if it did NOT ligate.  If it ligated, it's probably the font trying
+   *   to make it work without the reordering.
+   */
   if (start + 1 < end &&
       info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
-      info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH)
+      ((info[start].indic_category() == OT_Repha) ^
+       _hb_glyph_info_ligated (&info[start])))
   {
     unsigned int new_reph_pos;
     reph_position_t reph_pos = indic_plan->config->reph_pos;
 
-    /* XXX Figure out old behavior too */
+    assert (reph_pos != REPH_POS_DONT_CARE);
 
     /*       1. If reph should be positioned after post-base consonant forms,
      *          proceed to step 5.
      */
     if (reph_pos == REPH_POS_AFTER_POST)
     {
       goto reph_step_5;
     }
@@ -1338,17 +1454,16 @@ final_reordering_syllable (const hb_ot_s
 
     /*       3. If reph should be repositioned after the main consonant: find the
      *          first consonant not ligated with main, or find the first
      *          consonant that is not a potential pre-base reordering Ra.
      */
     if (reph_pos == REPH_POS_AFTER_MAIN)
     {
       new_reph_pos = base;
-      /* XXX Skip potential pre-base reordering Ra. */
       while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
 	new_reph_pos++;
       if (new_reph_pos < end)
         goto reph_move;
     }
 
     /*       4. If reph should be positioned before post-base consonant, find
      *          first post-base classified consonant not ligated with main. If no
@@ -1411,18 +1526,17 @@ final_reordering_syllable (const hb_ot_s
 	    new_reph_pos--;
 	  }
       }
       goto reph_move;
     }
 
     reph_move:
     {
-      /* Yay, one big cluster! Merge before moving. */
-      buffer->merge_clusters (start, end);
+      buffer->merge_clusters (start, new_reph_pos + 1);
 
       /* Move */
       hb_glyph_info_t reph = info[start];
       memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
       info[new_reph_pos] = reph;
       if (start < base && base <= new_reph_pos)
 	base--;
     }
@@ -1432,24 +1546,31 @@ final_reordering_syllable (const hb_ot_s
   /*   o Reorder pre-base reordering consonants:
    *
    *     If a pre-base reordering consonant is found, reorder it according to
    *     the following rules:
    */
 
   if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
   {
+    unsigned int pref_len = indic_plan->config->pref_len;
     for (unsigned int i = base + 1; i < end; i++)
       if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
       {
 	/*       1. Only reorder a glyph produced by substitution during application
 	 *          of the <pref> feature. (Note that a font may shape a Ra consonant with
 	 *          the feature generally but block it in certain contexts.)
 	 */
-	if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0)
+        /* Note: We just check that something got substituted.  We don't check that
+	 * the <pref> feature actually did it...
+	 *
+	 * If pref len is longer than one, then only reorder if it ligated.  If
+	 * pref len is one, only reorder if it didn't ligate with other things. */
+	if (_hb_glyph_info_substituted (&info[i]) &&
+	    ((pref_len == 1) ^ _hb_glyph_info_ligated (&info[i])))
 	{
 	  /*
 	   *       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.
 	   */
@@ -1460,17 +1581,17 @@ final_reordering_syllable (const hb_ot_s
 	   * We want to position matra after them.
 	   */
 	  if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
 	  {
 	    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
+	    /* In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a
 	     * split matra, it should be reordered to *before* the left part of such matra. */
 	    if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
 	    {
 	      unsigned int old_pos = i;
 	      for (unsigned int i = base + 1; i < old_pos; i++)
 		if (info[i].indic_category() == OT_M)
 		{
 		  new_pos--;
@@ -1510,21 +1631,30 @@ final_reordering_syllable (const hb_ot_s
     info[start].mask |= indic_plan->mask_array[INIT];
 
 
   /*
    * Finish off the clusters and go home!
    */
   if (hb_options ().uniscribe_bug_compatible)
   {
-    /* Uniscribe merges the entire cluster.
-     * This means, half forms are submerged into the main consonants cluster.
-     * This is unnecessary, and makes cursor positioning harder, but that's what
-     * Uniscribe does. */
-    buffer->merge_clusters (start, end);
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_TAMIL:
+      case HB_SCRIPT_SINHALA:
+        break;
+
+      default:
+	/* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
+	 * This means, half forms are submerged into the main consonants cluster.
+	 * This is unnecessary, and makes cursor positioning harder, but that's what
+	 * Uniscribe does. */
+	buffer->merge_clusters (start, end);
+	break;
+    }
   }
 }
 
 
 static void
 final_reordering (const hb_ot_shape_plan_t *plan,
 		  hb_font_t *font HB_UNUSED,
 		  hb_buffer_t *buffer)
@@ -1538,22 +1668,30 @@ final_reordering (const hb_ot_shape_plan
   for (unsigned int i = 1; i < count; i++)
     if (last_syllable != info[i].syllable()) {
       final_reordering_syllable (plan, buffer, last, i);
       last = i;
       last_syllable = info[last].syllable();
     }
   final_reordering_syllable (plan, buffer, last, count);
 
-  /* Zero syllables now... */
+  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+}
+
+
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+		 hb_font_t *font HB_UNUSED,
+		 hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
     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_segment_properties_t *props HB_UNUSED)
 {
   return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
 }
@@ -1626,17 +1764,17 @@ decompose_indic (const hb_ot_shape_norma
      */
 
     const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
 
     hb_codepoint_t glyph;
 
     if (hb_options ().uniscribe_bug_compatible ||
 	(c->font->get_glyph (ab, 0, &glyph) &&
-	 indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face)))
+	 indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
     {
       /* Ok, safe to use Uniscribe-style decomposition. */
       *a = 0x0DD9;
       *b = ab;
       return true;
     }
   }
 
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -55,16 +55,26 @@ other_features[] =
    * These features are applied all at once, after final_reordering.
    */
   HB_TAG('p','r','e','s'),
   HB_TAG('a','b','v','s'),
   HB_TAG('b','l','w','s'),
   HB_TAG('p','s','t','s'),
   /* Positioning features, though we don't care about the types. */
   HB_TAG('d','i','s','t'),
+  /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
+   * features.  The released Windows 8 version of the font (as well
+   * as the released spec) used 'mark' instead.  The Windows 8
+   * shaper however didn't apply 'mark' but did apply 'mkmk'.
+   * Perhaps it applied abvm/blwm.  This was fixed in a Windows 8
+   * update, so now it applies mark/mkmk.  We are guessing that
+   * it still applies abvm/blwm too.
+   */
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
 };
 
 static void
 setup_syllables (const hb_ot_shape_plan_t *plan,
 		 hb_font_t *font,
 		 hb_buffer_t *buffer);
 static void
 initial_reordering (const hb_ot_shape_plan_t *plan,
@@ -136,17 +146,17 @@ enum myanmar_category_t {
   OT_VS   = 30 /* Variation selectors */
 };
 
 
 static inline bool
 is_one_of (const hb_glyph_info_t &info, unsigned int flags)
 {
   /* If it ligated, all bets are off. */
-  if (is_a_ligature (info)) return false;
+  if (_hb_glyph_info_ligated (&info)) return false;
   return !!(FLAG (info.myanmar_category()) & 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! */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -274,19 +274,16 @@ hb_ot_shape_complex_categorize (const hb
     case HB_SCRIPT_MALAYALAM:
     case HB_SCRIPT_ORIYA:
     case HB_SCRIPT_TAMIL:
     case HB_SCRIPT_TELUGU:
 
     /* Unicode-3.0 additions */
     case HB_SCRIPT_SINHALA:
 
-    /* Unicode-4.1 additions */
-    case HB_SCRIPT_BUGINESE:
-
     /* Unicode-5.0 additions */
     case HB_SCRIPT_BALINESE:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_LEPCHA:
     case HB_SCRIPT_REJANG:
     case HB_SCRIPT_SUNDANESE:
 
@@ -331,16 +328,17 @@ hb_ot_shape_complex_categorize (const hb
       /* For Myanmar, we only want to use the Myanmar 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_myanmar;
       else
 	return &_hb_ot_complex_shaper_default;
 
     /* Unicode-4.1 additions */
+    case HB_SCRIPT_BUGINESE:
     case HB_SCRIPT_NEW_TAI_LUE:
 
     /* Unicode-5.1 additions */
     case HB_SCRIPT_CHAM:
 
     /* Unicode-5.2 additions */
     case HB_SCRIPT_TAI_THAM:
 
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc
@@ -261,17 +261,17 @@ initial_reordering_syllable (const hb_ot
 			     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, face, buffer, start, end); return;
   case broken_cluster:		initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
-  case non_sea_cluster:	initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return;
+  case non_sea_cluster:		initial_reordering_non_sea_cluster     (plan, face, buffer, start, end); return;
   }
 }
 
 static inline void
 insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
 		       hb_font_t *font,
 		       hb_buffer_t *buffer)
 {
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -255,31 +255,45 @@ position_mark (const hb_ot_shape_plan_t 
     case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
     case HB_UNICODE_COMBINING_CLASS_BELOW:
     case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
       /* Add gap, fall-through. */
       base_extents.height -= y_gap;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
-      pos.y_offset += base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
+      pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
+      /* Never shift up "below" marks. */
+      if ((y_gap > 0) == (pos.y_offset > 0))
+      {
+	base_extents.height -= pos.y_offset;
+	pos.y_offset = 0;
+      }
       base_extents.height += mark_extents.height;
       break;
 
     case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
     case HB_UNICODE_COMBINING_CLASS_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
       /* Add gap, fall-through. */
       base_extents.y_bearing += y_gap;
       base_extents.height -= y_gap;
 
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
     case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
-      pos.y_offset += base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
+      pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
+      /* Don't shift down "above" marks too much. */
+      if ((y_gap > 0) != (pos.y_offset > 0))
+      {
+	unsigned int correction = -pos.y_offset / 2;
+	base_extents.y_bearing += correction;
+	base_extents.height -= correction;
+	pos.y_offset += correction;
+      }
       base_extents.y_bearing -= mark_extents.height;
       base_extents.height += mark_extents.height;
       break;
   }
 }
 
 static inline void
 position_around_base (const hb_ot_shape_plan_t *plan,
@@ -295,35 +309,35 @@ position_around_base (const hb_ot_shape_
   {
     /* If extents don't work, zero marks and go home. */
     zero_mark_advances (buffer, base + 1, end);
     return;
   }
   base_extents.x_bearing += buffer->pos[base].x_offset;
   base_extents.y_bearing += buffer->pos[base].y_offset;
 
-  unsigned int lig_id = get_lig_id (buffer->info[base]);
-  unsigned int num_lig_components = get_lig_num_comps (buffer->info[base]);
+  unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
+  unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
 
   hb_position_t x_offset = 0, y_offset = 0;
   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 = 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;
+	unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[i]);
+	unsigned int this_lig_component = _hb_glyph_info_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)
 	  this_lig_component = num_lig_components - 1;
 	if (last_lig_component != this_lig_component)
 	{
 	  last_lig_component = this_lig_component;
 	  last_combining_class = 255;
 	  component_extents = base_extents;
@@ -411,46 +425,57 @@ void
 
 
 /* Performs old-style TrueType kerning. */
 void
 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
 			    hb_font_t *font,
 			    hb_buffer_t  *buffer)
 {
-  unsigned int count = buffer->len;
   hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
 					      HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
+  if (!kern_mask) return;
+
+  unsigned int count = buffer->len;
 
   OT::hb_apply_context_t c (1, font, buffer);
   c.set_lookup_mask (kern_mask);
   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
 
-  for (buffer->idx = 0; buffer->idx < count;)
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+
+  for (unsigned int idx = 0; idx < count;)
   {
-    OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, buffer->idx, 1);
+    OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
     if (!skippy_iter.next ())
     {
-      buffer->idx++;
+      idx++;
       continue;
     }
 
-    hb_position_t x_kern, y_kern, kern1, kern2;
-    font->get_glyph_kerning_for_direction (buffer->info[buffer->idx].codepoint,
-					   buffer->info[skippy_iter.idx].codepoint,
+    hb_position_t x_kern, y_kern;
+    font->get_glyph_kerning_for_direction (info[idx].codepoint,
+					   info[skippy_iter.idx].codepoint,
 					   buffer->props.direction,
 					   &x_kern, &y_kern);
 
-    kern1 = x_kern >> 1;
-    kern2 = x_kern - kern1;
-    buffer->pos[buffer->idx].x_advance += kern1;
-    buffer->pos[skippy_iter.idx].x_advance += kern2;
-    buffer->pos[skippy_iter.idx].x_offset += kern2;
+    if (x_kern)
+    {
+      hb_position_t kern1 = x_kern >> 1;
+      hb_position_t kern2 = x_kern - kern1;
+      pos[idx].x_advance += kern1;
+      pos[skippy_iter.idx].x_advance += kern2;
+      pos[skippy_iter.idx].x_offset += kern2;
+    }
 
-    kern1 = y_kern >> 1;
-    kern2 = y_kern - kern1;
-    buffer->pos[buffer->idx].y_advance += kern1;
-    buffer->pos[skippy_iter.idx].y_advance += kern2;
-    buffer->pos[skippy_iter.idx].y_offset += kern2;
+    if (y_kern)
+    {
+      hb_position_t kern1 = y_kern >> 1;
+      hb_position_t kern2 = y_kern - kern1;
+      pos[idx].y_advance += kern1;
+      pos[skippy_iter.idx].y_advance += kern2;
+      pos[skippy_iter.idx].y_offset += kern2;
+    }
 
-    buffer->idx = skippy_iter.idx;
+    idx = skippy_iter.idx;
   }
 }
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -127,45 +127,47 @@ 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 (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
 {
   hb_codepoint_t a, b, a_glyph, b_glyph;
+  hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
 
   if (!c->decompose (c, ab, &a, &b) ||
-      (b && !c->font->get_glyph (b, 0, &b_glyph)))
+      (b && !font->get_glyph (b, 0, &b_glyph)))
     return 0;
 
-  bool has_a = c->font->get_glyph (a, 0, &a_glyph);
+  bool has_a = font->get_glyph (a, 0, &a_glyph);
   if (shortest && has_a) {
     /* Output a and b */
-    output_char (c->buffer, a, a_glyph);
+    output_char (buffer, a, a_glyph);
     if (likely (b)) {
-      output_char (c->buffer, b, b_glyph);
+      output_char (buffer, b, b_glyph);
       return 2;
     }
     return 1;
   }
 
   unsigned int ret;
   if ((ret = decompose (c, shortest, a))) {
     if (b) {
-      output_char (c->buffer, b, b_glyph);
+      output_char (buffer, b, b_glyph);
       return ret + 1;
     }
     return ret;
   }
 
   if (has_a) {
-    output_char (c->buffer, a, a_glyph);
+    output_char (buffer, a, a_glyph);
     if (likely (b)) {
-      output_char (c->buffer, b, b_glyph);
+      output_char (buffer, b, b_glyph);
       return 2;
     }
     return 1;
   }
 
   return 0;
 }
 
@@ -209,44 +211,45 @@ decompose_current_character (const hb_ot
   else
     next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
 }
 
 static inline void
 handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
 {
   hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
   for (; buffer->idx < end - 1;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       /* The next two lines are some ugly lines... But work. */
-      if (c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
       {
 	buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
       }
       else
       {
         /* Just pass on the two characters separately, let GSUB do its magic. */
-	set_glyph (buffer->cur(), c->font);
+	set_glyph (buffer->cur(), font);
 	buffer->next_glyph ();
-	set_glyph (buffer->cur(), c->font);
+	set_glyph (buffer->cur(), font);
 	buffer->next_glyph ();
       }
       /* Skip any further variation selectors. */
       while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
       {
-	set_glyph (buffer->cur(), c->font);
+	set_glyph (buffer->cur(), font);
 	buffer->next_glyph ();
       }
     } else {
-      set_glyph (buffer->cur(), c->font);
+      set_glyph (buffer->cur(), font);
       buffer->next_glyph ();
     }
   }
   if (likely (buffer->idx < end)) {
-    set_glyph (buffer->cur(), c->font);
+    set_glyph (buffer->cur(), font);
     buffer->next_glyph ();
   }
 }
 
 static inline void
 decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
 {
   hb_buffer_t * const buffer = c->buffer;
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -285,47 +285,50 @@ hb_ensure_native_direction (hb_buffer_t 
 /* Substitute */
 
 static inline void
 hb_ot_mirror_chars (hb_ot_shape_context_t *c)
 {
   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
     return;
 
-  hb_unicode_funcs_t *unicode = c->buffer->unicode;
+  hb_buffer_t *buffer = c->buffer;
+  hb_unicode_funcs_t *unicode = buffer->unicode;
   hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
 
-  unsigned int count = c->buffer->len;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = unicode->mirroring (c->buffer->info[i].codepoint);
-    if (likely (codepoint == c->buffer->info[i].codepoint))
-      c->buffer->info[i].mask |= rtlm_mask;
+    hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+    if (likely (codepoint == info[i].codepoint))
+      info[i].mask |= rtlm_mask;
     else
-      c->buffer->info[i].codepoint = codepoint;
+      info[i].codepoint = codepoint;
   }
 }
 
 static inline void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
   hb_ot_map_t *map = &c->plan->map;
+  hb_buffer_t *buffer = c->buffer;
 
   hb_mask_t global_mask = map->get_global_mask ();
-  c->buffer->reset_masks (global_mask);
+  buffer->reset_masks (global_mask);
 
   if (c->plan->shaper->setup_masks)
-    c->plan->shaper->setup_masks (c->plan, c->buffer, c->font);
+    c->plan->shaper->setup_masks (c->plan, buffer, c->font);
 
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
     const hb_feature_t *feature = &c->user_features[i];
     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
       unsigned int shift;
       hb_mask_t mask = map->get_mask (feature->tag, &shift);
-      c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+      buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
     }
   }
 }
 
 static inline void
 hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
 {
   /* Normalization process sets up glyph_index(), we just copy it. */
@@ -333,56 +336,63 @@ hb_ot_map_glyphs_fast (hb_buffer_t  *buf
   for (unsigned int i = 0; i < count; i++)
     buffer->info[i].codepoint = buffer->info[i].glyph_index();
 }
 
 static inline void
 hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
 {
   unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
-				       HB_OT_LAYOUT_GLYPH_PROPS_MARK :
-				       HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+    _hb_glyph_info_set_glyph_props (&info[i],
+				    _hb_glyph_info_get_general_category (&info[i])
+				    == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ?
+				    HB_OT_LAYOUT_GLYPH_PROPS_MARK :
+				    HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
 }
 
 static inline void
 hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
+  hb_buffer_t *buffer = c->buffer;
+
   if (c->plan->shaper->preprocess_text)
-    c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+    c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
 
   hb_ot_mirror_chars (c);
 
-  HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index);
+  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
 
-  _hb_ot_shape_normalize (c->plan, c->buffer, c->font);
+  _hb_ot_shape_normalize (c->plan, 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_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
 
-  hb_ot_map_glyphs_fast (c->buffer);
+  hb_ot_map_glyphs_fast (buffer);
 
-  HB_BUFFER_DEALLOCATE_VAR (c->buffer, glyph_index);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
 }
 
 static inline void
 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_substitute_start (c->font, c->buffer);
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_ot_layout_substitute_start (c->font, buffer);
 
   if (!hb_ot_layout_has_glyph_classes (c->face))
     hb_synthesize_glyph_classes (c);
 
-  c->plan->substitute (c->font, c->buffer);
+  c->plan->substitute (c->font, buffer);
 
-  hb_ot_layout_substitute_finish (c->font, c->buffer);
+  hb_ot_layout_substitute_finish (c->font, buffer);
 
   return;
 }
 
 static inline void
 hb_ot_substitute (hb_ot_shape_context_t *c)
 {
   hb_ot_substitute_default (c);
@@ -403,37 +413,40 @@ zero_mark_widths_by_unicode (hb_buffer_t
     }
 }
 
 static inline void
 zero_mark_widths_by_gdef (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    if ((buffer->info[i].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
+    if (_hb_glyph_info_is_mark (&buffer->info[i]))
     {
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
 }
 
 static inline void
 hb_ot_position_default (hb_ot_shape_context_t *c)
 {
+  hb_direction_t direction = c->buffer->props.direction;
   unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
   for (unsigned int i = 0; i < count; i++)
   {
-    c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint,
-					      c->buffer->props.direction,
-					      &c->buffer->pos[i].x_advance,
-					      &c->buffer->pos[i].y_advance);
-    c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
-						  c->buffer->props.direction,
-						  &c->buffer->pos[i].x_offset,
-						  &c->buffer->pos[i].y_offset);
+    c->font->get_glyph_advance_for_direction (info[i].codepoint,
+					      direction,
+					      &pos[i].x_advance,
+					      &pos[i].y_advance);
+    c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+						  direction,
+						  &pos[i].x_offset,
+						  &pos[i].y_offset);
 
   }
 }
 
 static inline bool
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
   bool ret = false;
@@ -455,32 +468,35 @@ hb_ot_position_complex (hb_ot_shape_cont
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
       break;
   }
 
   if (hb_ot_layout_has_positioning (c->face))
   {
+    hb_glyph_info_t *info = c->buffer->info;
+    hb_glyph_position_t *pos = c->buffer->pos;
+
     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
 
     for (unsigned int i = 0; i < count; i++) {
-      c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint,
+      c->font->add_glyph_origin_for_direction (info[i].codepoint,
 					       HB_DIRECTION_LTR,
-					       &c->buffer->pos[i].x_offset,
-					       &c->buffer->pos[i].y_offset);
+					       &pos[i].x_offset,
+					       &pos[i].y_offset);
     }
 
     c->plan->position (c->font, c->buffer);
 
     for (unsigned int i = 0; i < count; i++) {
-      c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
+      c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
 						    HB_DIRECTION_LTR,
-						    &c->buffer->pos[i].x_offset,
-						    &c->buffer->pos[i].y_offset);
+						    &pos[i].x_offset,
+						    &pos[i].y_offset);
     }
 
     ret = true;
   }
 
   switch (c->plan->shaper->zero_width_marks)
   {
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
@@ -541,17 +557,17 @@ hb_ot_hide_default_ignorables (hb_ot_sha
   } space_status = SPACE_DONT_KNOW;
 
   unsigned int count = c->buffer->len;
   hb_glyph_info_t *info = c->buffer->info;
   hb_glyph_position_t *pos = c->buffer->pos;
   unsigned int j = 0;
   for (unsigned int i = 0; i < count; i++)
   {
-    if (unlikely (!is_a_ligature (info[i]) &&
+    if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
 		  _hb_glyph_info_is_default_ignorable (&info[i])))
     {
       if (space_status == SPACE_DONT_KNOW)
 	space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
 
       if (space_status == SPACE_AVAILABLE)
       {
 	info[i].codepoint = space;
@@ -577,34 +593,32 @@ hb_ot_hide_default_ignorables (hb_ot_sha
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   c->buffer->deallocate_var_all ();
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
 
-  HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0);
-  HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1);
+  _hb_buffer_allocate_unicode_vars (c->buffer);
 
   c->buffer->clear_output ();
 
   hb_set_unicode_props (c->buffer);
   hb_insert_dotted_circle (c->buffer, c->font);
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
 
   hb_ot_substitute (c);
   hb_ot_position (c);
 
   hb_ot_hide_default_ignorables (c);
 
-  HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1);
-  HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
+  _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
 
   c->buffer->deallocate_var_all ();
 }
 
 
 hb_bool_t
--- 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 21
+#define HB_VERSION_MICRO 23
 
-#define HB_VERSION_STRING "0.9.21"
+#define HB_VERSION_STRING "0.9.23"
 
 #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/test-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/test-buffer-serialize.cc
@@ -29,17 +29,20 @@
 #endif
 
 #include "hb.h"
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
 #ifdef HAVE_GLIB
-#include <glib.h>
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 int
 main (int argc, char **argv)
 {
   hb_blob_t *blob = NULL;
--- a/gfx/harfbuzz/src/test-size-params.cc
+++ b/gfx/harfbuzz/src/test-size-params.cc
@@ -27,17 +27,20 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "hb.h"
 #include "hb-ot.h"
 
 #ifdef HAVE_GLIB
-#include <glib.h>
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 int
 main (int argc, char **argv)
 {
   hb_blob_t *blob = NULL;
--- a/gfx/harfbuzz/src/test-would-substitute.cc
+++ b/gfx/harfbuzz/src/test-would-substitute.cc
@@ -27,17 +27,20 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "hb.h"
 #include "hb-ot.h"
 
 #ifdef HAVE_GLIB
-#include <glib.h>
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif
 
--- a/gfx/harfbuzz/src/test.cc
+++ b/gfx/harfbuzz/src/test.cc
@@ -26,17 +26,20 @@
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "hb.h"
 
 #ifdef HAVE_GLIB
-#include <glib.h>
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
 #ifdef HAVE_FREETYPE
 #include "hb-ft.h"
 #endif