Bug 826226 - update harfbuzz to release 0.9.10. r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Tue, 08 Jan 2013 14:03:18 +0000
changeset 118094 a1e69e2b30c5d2305c2e6d0ad338aa1a05b6207b
parent 118093 1f7a46d13daa40cf17c99c97c99560310846b200
child 118095 6ff7c9712ff250b0fe28620fda696d6df5989c64
push id24150
push userryanvm@gmail.com
push dateWed, 09 Jan 2013 01:07:17 +0000
treeherdermozilla-central@564336aa34f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs826226
milestone21.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 826226 - update harfbuzz to release 0.9.10. r=jdaggett
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/check-exported-symbols.sh
gfx/harfbuzz/src/check-internal-symbols.sh
gfx/harfbuzz/src/hb-atomic-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-common.cc
gfx/harfbuzz/src/hb-coretext.cc
gfx/harfbuzz/src/hb-coretext.h
gfx/harfbuzz/src/hb-fallback-shape.cc
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-graphite2.h
gfx/harfbuzz/src/hb-icu-le.cc
gfx/harfbuzz/src/hb-object-private.hh
gfx/harfbuzz/src/hb-old.cc
gfx/harfbuzz/src/hb-open-file-private.hh
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-head-table.hh
gfx/harfbuzz/src/hb-ot-hhea-table.hh
gfx/harfbuzz/src/hb-ot-hmtx-table.hh
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-maxp-table.hh
gfx/harfbuzz/src/hb-ot-name-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-ot-tag.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-set-private.hh
gfx/harfbuzz/src/hb-set.cc
gfx/harfbuzz/src/hb-set.h
gfx/harfbuzz/src/hb-shape-plan-private.hh
gfx/harfbuzz/src/hb-shape-plan.cc
gfx/harfbuzz/src/hb-shape-plan.h
gfx/harfbuzz/src/hb-shape.h
gfx/harfbuzz/src/hb-tt-font.cc
gfx/harfbuzz/src/hb-ucdn.cc
gfx/harfbuzz/src/hb-uniscribe.cc
gfx/harfbuzz/src/hb-utf-private.hh
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/test-size-params.cc
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -190,19 +190,23 @@ DIST_SUBDIRS += hb-ucdn
 
 # Put the library together
 
 if OS_WIN32
 export_symbols = -export-symbols harfbuzz.def
 harfbuzz_def_dependency = harfbuzz.def
 libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
 else
+if HAVE_ICU
+libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
+else
 # Use a C linker, not C++; Don't link to libstdc++
 libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
 endif
+endif
 
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
 nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
 libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
@@ -242,27 +246,35 @@ arabic-table: gen-arabic-table.py Arabic
 
 .PHONY: unicode-tables arabic-table indic-table
 
 EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
 $(srcdir)/hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
 	$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
 	mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
 
-noinst_PROGRAMS = main test-would-substitute
+noinst_PROGRAMS = main test test-would-substitute test-size-params
 bin_PROGRAMS =
 
 main_SOURCES = main.cc
 main_CPPFLAGS = $(HBCFLAGS)
 main_LDADD = libharfbuzz.la $(HBLIBS)
 
+test_SOURCES = test.cc
+test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+
 test_would_substitute_SOURCES = test-would-substitute.cc
 test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
 test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
 
+test_size_params_SOURCES = test-size-params.cc
+test_size_params_CPPFLAGS = $(HBCFLAGS)
+test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+
 dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
 	check-header-guards.sh \
 	check-exported-symbols.sh \
 	check-includes.sh \
 	check-internal-symbols.sh \
 	$(NULL)
 
--- a/gfx/harfbuzz/src/check-exported-symbols.sh
+++ b/gfx/harfbuzz/src/check-exported-symbols.sh
@@ -19,17 +19,17 @@ defs="harfbuzz.def"
 tested=false
 for def in $defs; do
 	lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
 	so=.libs/lib${lib}.so
 	if test -f "$so"; then
 		echo "Checking that $so has the same symbol list as $def"
 		{
 			echo EXPORTS
-			nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>' | cut -d' ' -f3
+			nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3
 			stat=1
 			# cheat: copy the last line from the def file!
 			tail -n1 "$def"
 		} | diff "$def" - >&2 || stat=1
 		tested=true
 	fi
 done
 if ! $tested; then
--- a/gfx/harfbuzz/src/check-internal-symbols.sh
+++ b/gfx/harfbuzz/src/check-internal-symbols.sh
@@ -14,17 +14,17 @@ else
 	exit 77
 fi
 
 tested=false
 for suffix in .so; do
 	so=`echo .libs/libharfbuzz$suffix`
 	if test -f "$so"; then
 		echo "Checking that we are not exposing internal symbols"
-		if nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
+		if nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' T _fini\>\| T _init\>\| T hb_\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>'; then
 			echo "Ouch, internal symbols exposed"
 			stat=1
 		fi
 		tested=true
 	fi
 done
 if ! $tested; then
 	echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
--- a/gfx/harfbuzz/src/hb-atomic-private.hh
+++ b/gfx/harfbuzz/src/hb-atomic-private.hh
@@ -54,32 +54,45 @@
 #define HBMemoryBarrier MemoryBarrier
 #else
 static inline void HBMemoryBarrier (void) {
   long dummy = 0;
   InterlockedExchange (&dummy, 1);
 }
 #endif
 
-typedef long hb_atomic_int_t;
+typedef LONG hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)	InterlockedExchangeAdd (&(AI), (V))
 
 #define hb_atomic_ptr_get(P)		(HBMemoryBarrier (), (void *) *(P))
 #define hb_atomic_ptr_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
 #elif !defined(HB_NO_MT) && defined(__APPLE__)
 
 #include <libkern/OSAtomic.h>
+#ifdef __MAC_OS_X_MIN_REQUIRED
+#include <AvailabilityMacros.h>
+#elif defined(__IPHONE_OS_MIN_REQUIRED)
+#include <Availability.h>
+#endif
 
 typedef int32_t hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)	(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
 
 #define hb_atomic_ptr_get(P)		(OSMemoryBarrier (), (void *) *(P))
+#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
 #define hb_atomic_ptr_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#else
+#if __ppc64__ || __x86_64__
+#define hb_atomic_ptr_cmpexch(P,O,N)    OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+#else
+#define hb_atomic_ptr_cmpexch(P,O,N)    OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+#endif
+#endif
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 typedef int hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)	__sync_fetch_and_add (&(AI), (V))
 
 #define hb_atomic_ptr_get(P)		(void *) (__sync_synchronize (), *(P))
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -488,18 +488,18 @@ hb_buffer_t::merge_out_clusters (unsigne
 
   for (unsigned int i = start; i < end; i++)
     out_info[i].cluster = cluster;
 }
 
 void
 hb_buffer_t::guess_segment_properties (void)
 {
-  if (unlikely (!len)) return;
-  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+	  (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
 
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
     for (unsigned int i = 0; i < len; i++) {
       hb_script_t script = unicode->script (info[i].codepoint);
       if (likely (script != HB_SCRIPT_COMMON &&
 		  script != HB_SCRIPT_INHERITED &&
 		  script != HB_SCRIPT_UNKNOWN)) {
@@ -1066,18 +1066,18 @@ hb_buffer_normalize_glyphs (hb_buffer_t 
 }
 
 
 /*
  * Serialize
  */
 
 static const char *serialize_formats[] = {
-  "TEXT",
-  "JSON",
+  "text",
+  "json",
   NULL
 };
 
 const char **
 hb_buffer_serialize_list_formats (void)
 {
   return serialize_formats;
 }
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -358,18 +358,17 @@ hb_script_get_horizontal_direction (hb_s
 
 
 /* hb_user_data_array_t */
 
 bool
 hb_user_data_array_t::set (hb_user_data_key_t *key,
 			   void *              data,
 			   hb_destroy_func_t   destroy,
-			   hb_bool_t           replace,
-			   hb_mutex_t         &lock)
+			   hb_bool_t           replace)
 {
   if (!key)
     return false;
 
   if (replace) {
     if (!data && !destroy) {
       items.remove (key, lock);
       return true;
@@ -377,30 +376,23 @@ hb_user_data_array_t::set (hb_user_data_
   }
   hb_user_data_item_t item = {key, data, destroy};
   bool ret = !!items.replace_or_insert (item, lock, replace);
 
   return ret;
 }
 
 void *
-hb_user_data_array_t::get (hb_user_data_key_t *key,
-			   hb_mutex_t         &lock)
+hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
   hb_user_data_item_t item = {NULL };
 
   return items.find (key, &item, lock) ? item.data : NULL;
 }
 
-void
-hb_user_data_array_t::finish (hb_mutex_t &lock)
-{
-  items.finish (lock);
-}
-
 
 /* hb_version */
 
 void
 hb_version (unsigned int *major,
 	    unsigned int *minor,
 	    unsigned int *micro)
 {
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -24,20 +24,16 @@
  *
  * Mozilla Author(s): Jonathan Kew
  * Google Author(s): Behdad Esfahbod
  */
 
 #define HB_SHAPER coretext
 #include "hb-shaper-impl-private.hh"
 
-#define GlyphID GlyphID_mac
-#include <ApplicationServices/ApplicationServices.h>
-#undef GlyphID
-
 #include "hb-coretext.h"
 
 
 #ifndef HB_DEBUG_CORETEXT
 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
 #endif
 
 
@@ -90,16 +86,24 @@ hb_coretext_shaper_face_data_t *
 
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
   CFRelease (data->cg_font);
   free (data);
 }
 
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  return face_data->cg_font;
+}
+
 
 /*
  * shaper font data
  */
 
 struct hb_coretext_shaper_font_data_t {
   CTFontRef ct_font;
 };
@@ -148,29 +152,29 @@ hb_coretext_shaper_shape_plan_data_t *
   return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
 {
 }
 
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+  return font_data->ct_font;
+}
+
 
 /*
  * shaper
  */
 
-CTFontRef
-hb_coretext_font_get_ct_font (hb_font_t *font)
-{
-  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return 0;
-  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
-  return font_data->ct_font;
-}
-
 hb_bool_t
 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 		    hb_font_t          *font,
                     hb_buffer_t        *buffer,
                     const hb_feature_t *features,
                     unsigned int        num_features)
 {
   hb_face_t *face = font->face;
@@ -207,55 +211,49 @@ hb_bool_t
 
   CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault,
                                                                pchars, chars_len,
                                                                kCFAllocatorNull);
 
   CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault,
                                               (const void**) &kCTFontAttributeName,
                                               (const void**) &font_data->ct_font,
-                                              1, // count of attributes
+                                              1, /* count of attributes */
                                               &kCFTypeDictionaryKeyCallBacks,
                                               &kCFTypeDictionaryValueCallBacks);
 
-  // TODO: support features
+  /* TODO: support features */
 
-  // Now we can create an attributed string
   CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs);
   CFRelease (string_ref);
   CFRelease (attrs);
 
-  // Create the CoreText line from our string, then we're done with it
   CTLineRef line = CTLineCreateWithAttributedString (attr_string);
   CFRelease (attr_string);
 
-  // and finally retrieve the glyph data and store into the gfxTextRun
   CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
   unsigned int num_runs = CFArrayGetCount (glyph_runs);
 
-  // Iterate through the glyph runs.
   bool success = true;
   buffer->len = 0;
 
   const CFRange range_all = CFRangeMake (0, 0);
 
   for (unsigned int i = 0; i < num_runs; i++) {
     CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
 
     unsigned int num_glyphs = CTRunGetGlyphCount (run);
     if (num_glyphs == 0)
       continue;
 
     buffer->ensure (buffer->len + num_glyphs);
 
-    // retrieve the laid-out glyph data from the CTRun
-
-    // Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds,
-    // and so copying data to our own buffer with CTRunGetGlyphs will be
-    // extremely rare.
+    /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds,
+     * and so copying data to our own buffer with CTRunGetGlyphs will be
+     * extremely rare. */
 
     unsigned int scratch_size;
     char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
 
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
   scratch += (len) * sizeof ((name)[0]); \
   scratch_size -= (len) * sizeof ((name)[0]);
@@ -289,17 +287,17 @@ hb_bool_t
       double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
 
       hb_glyph_info_t *info = &buffer->info[buffer->len];
       hb_glyph_position_t *pos = &buffer->pos[buffer->len];
 
       info->codepoint = glyphs[j];
       info->cluster = string_indices[j];
 
-      // currently, we do all x-positioning by setting the advance, we never use x-offset
+      /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
       info->mask = advance;
       info->var1.u32 = 0;
       info->var2.u32 = positions[j].y;
 
       buffer->len++;
     }
   }
 
@@ -311,38 +309,38 @@ hb_bool_t
     hb_glyph_position_t *pos = &buffer->pos[i];
 
     /* TODO vertical */
     pos->x_advance = info->mask;
     pos->x_offset = info->var1.u32;
     pos->y_offset = info->var2.u32;
   }
 
-  // Fix up clusters so that we never return out-of-order indices;
-  // if core text has reordered glyphs, we'll merge them to the
-  // beginning of the reordered cluster.
-  // This does *not* mean we'll form the same clusters as Uniscribe
-  // or the native OT backend, only that the cluster indices will be
-  // non-decreasing in the output buffer.
+  /* Fix up clusters so that we never return out-of-order indices;
+   * if core text has reordered glyphs, we'll merge them to the
+   * beginning of the reordered cluster.
+   *
+   * This does *not* mean we'll form the same clusters as Uniscribe
+   * or the native OT backend, only that the cluster indices will be
+   * monotonic in the output buffer. */
   if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
     unsigned int prev_cluster = 0;
     for (unsigned int i = 0; i < count; i++) {
       unsigned int curr_cluster = buffer->info[i].cluster;
       if (curr_cluster < prev_cluster) {
         for (unsigned int j = i; j > 0; j--) {
           if (buffer->info[j - 1].cluster > curr_cluster)
             buffer->info[j - 1].cluster = curr_cluster;
           else
             break;
         }
       }
       prev_cluster = curr_cluster;
     }
   } else {
-    // For RTL runs, we make them non-increasing instead.
     unsigned int prev_cluster = (unsigned int)-1;
     for (unsigned int i = 0; i < count; i++) {
       unsigned int curr_cluster = buffer->info[i].cluster;
       if (curr_cluster > prev_cluster) {
         for (unsigned int j = i; j > 0; j--) {
           if (buffer->info[j - 1].cluster < curr_cluster)
             buffer->info[j - 1].cluster = curr_cluster;
           else
--- a/gfx/harfbuzz/src/hb-coretext.h
+++ b/gfx/harfbuzz/src/hb-coretext.h
@@ -29,15 +29,18 @@
 
 #include "hb.h"
 
 #include <ApplicationServices/ApplicationServices.h>
 
 HB_BEGIN_DECLS
 
 
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face);
+
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font);
 
 
 HB_END_DECLS
 
 #endif /* HB_CORETEXT_H */
--- a/gfx/harfbuzz/src/hb-fallback-shape.cc
+++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
@@ -30,41 +30,41 @@
 
 /*
  * shaper face data
  */
 
 struct hb_fallback_shaper_face_data_t {};
 
 hb_fallback_shaper_face_data_t *
-_hb_fallback_shaper_face_data_create (hb_face_t *face)
+_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
 {
   return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data)
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
 {
 }
 
 
 /*
  * shaper font data
  */
 
 struct hb_fallback_shaper_font_data_t {};
 
 hb_fallback_shaper_font_data_t *
-_hb_fallback_shaper_font_data_create (hb_font_t *font)
+_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 {
   return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data)
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
 {
 }
 
 
 /*
  * shaper shape_plan data
  */
 
@@ -84,17 +84,17 @@ void
 }
 
 
 /*
  * shaper
  */
 
 hb_bool_t
-_hb_fallback_shape (hb_shape_plan_t    *shape_plan,
+_hb_fallback_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
 		    hb_font_t          *font,
 		    hb_buffer_t        *buffer,
 		    const hb_feature_t *features HB_UNUSED,
 		    unsigned int        num_features HB_UNUSED)
 {
   hb_codepoint_t space;
   font->get_glyph (' ', 0, &space);
 
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -329,17 +329,17 @@ hb_glib_unicode_decompose (hb_unicode_fu
     ret = true;
   }
 
   g_free (normalized);
   return ret;
 }
 
 static unsigned int
-hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 					 hb_codepoint_t      u,
 					 hb_codepoint_t     *decomposed,
 					 void               *user_data HB_UNUSED)
 {
 #if GLIB_CHECK_VERSION(2,29,12)
   return g_unichar_fully_decompose (u, TRUE, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
 #endif
 
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -108,17 +108,17 @@ hb_graphite2_shaper_face_data_t *
   }
   hb_blob_destroy (silf_blob);
 
   hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
   if (unlikely (!data))
     hb_blob_destroy (silf_blob);
 
   data->face = face;
-  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_default);
+  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
     free (data);
     return NULL;
   }
 
   return data;
 }
@@ -136,16 +136,23 @@ void
     free (old);
   }
 
   gr_face_destroy (data->grface);
 
   free (data);
 }
 
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face)
+{
+  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
+  return HB_SHAPER_DATA_GET (face)->grface;
+}
+
 
 /*
  * shaper font data
  */
 
 static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
 {
   return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
@@ -163,16 +170,23 @@ hb_graphite2_shaper_font_data_t *
 }
 
 void
 _hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
 {
   gr_font_destroy (data);
 }
 
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font)
+{
+  if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
+  return HB_SHAPER_DATA_GET (font);
+}
+
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_graphite2_shaper_shape_plan_data_t {};
 
 hb_graphite2_shaper_shape_plan_data_t *
@@ -306,20 +320,28 @@ hb_bool_t
     }
     clusters[ci].num_glyphs++;
 
     if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
 	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
   }
   ci++;
 
-  buffer->clear_output ();
+  //buffer->clear_output ();
   for (unsigned int i = 0; i < ci; ++i)
-    buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph);
-  buffer->swap_buffers ();
+  {
+    for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
+    {
+      hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
+      info->codepoint = gids[clusters[i].base_glyph + j];
+      info->cluster = gr_cinfo_base(gr_seg_cinfo(seg, clusters[i].base_char));
+    }
+  }
+  buffer->len = glyph_count;
+  //buffer->swap_buffers ();
 
   if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
     curradvx = gr_seg_advance_X(seg);
 
   hb_glyph_position_t *pPos;
   for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
        is; pPos++, is = gr_slot_next_in_segment (is))
   {
--- a/gfx/harfbuzz/src/hb-graphite2.h
+++ b/gfx/harfbuzz/src/hb-graphite2.h
@@ -28,13 +28,19 @@
 
 #include "hb.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
 
-/* TODO add gr_font/face etc getters and other glue API */
+
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face);
+
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font);
+
 
 HB_END_DECLS
 
 #endif /* HB_GRAPHITE2_H */
--- a/gfx/harfbuzz/src/hb-icu-le.cc
+++ b/gfx/harfbuzz/src/hb-icu-le.cc
@@ -38,23 +38,23 @@
 
 /*
  * shaper face data
  */
 
 struct hb_icu_le_shaper_face_data_t {};
 
 hb_icu_le_shaper_face_data_t *
-_hb_icu_le_shaper_face_data_create (hb_face_t *face)
+_hb_icu_le_shaper_face_data_create (hb_face_t *face HB_UNUSED)
 {
   return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data)
+_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data HB_UNUSED)
 {
 }
 
 
 /*
  * shaper font data
  */
 
@@ -83,17 +83,17 @@ void
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_icu_le_shaper_shape_plan_data_t {};
 
 hb_icu_le_shaper_shape_plan_data_t *
-_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
 					  const hb_feature_t *user_features,
 					  unsigned int        num_user_features)
 {
   return (hb_icu_le_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_icu_le_shaper_shape_plan_data_destroy (hb_icu_le_shaper_shape_plan_data_t *data)
@@ -110,17 +110,17 @@ hb_bool_t
 		  hb_font_t          *font,
 		  hb_buffer_t        *buffer,
 		  const hb_feature_t *features,
 		  unsigned int        num_features)
 {
   LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font);
   le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script);
   le_int32 language_code = -1 /* TODO */;
-  le_int32 typography_flags = 3; // essential for ligatures and kerning
+  le_int32 typography_flags = 3; /* Needed for ligatures and kerning */
   LEErrorCode status = LE_NO_ERROR;
   le_engine *le = le_create ((const le_font *) font_instance,
 			     script_code,
 			     language_code,
 			     typography_flags,
 			     &status);
   if (status != LE_NO_ERROR)
   { le_close (le); return false; }
--- a/gfx/harfbuzz/src/hb-object-private.hh
+++ b/gfx/harfbuzz/src/hb-object-private.hh
@@ -60,71 +60,68 @@ struct hb_reference_count_t
 
   inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; }
 
 };
 
 
 /* user_data */
 
-#define HB_USER_DATA_ARRAY_INIT {HB_LOCKABLE_SET_INIT}
+#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
 struct hb_user_data_array_t
 {
   /* TODO Add tracing. */
 
   struct hb_user_data_item_t {
     hb_user_data_key_t *key;
     void *data;
     hb_destroy_func_t destroy;
 
     inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
     inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
 
     void finish (void) { if (destroy) destroy (data); }
   };
 
+  hb_mutex_t lock;
   hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items;
 
-  inline void init (void) { items.init (); }
+  inline void init (void) { lock.init (); items.init (); }
 
   HB_INTERNAL bool set (hb_user_data_key_t *key,
 			void *              data,
 			hb_destroy_func_t   destroy,
-			hb_bool_t           replace,
-			hb_mutex_t         &lock);
+			hb_bool_t           replace);
 
-  HB_INTERNAL void *get (hb_user_data_key_t *key,
-			hb_mutex_t          &lock);
+  HB_INTERNAL void *get (hb_user_data_key_t *key);
 
-  HB_INTERNAL void finish (hb_mutex_t &lock);
+  inline void finish (void) { items.finish (lock); lock.finish (); }
 };
 
 
 /* object_header */
 
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  hb_mutex_t mutex;
   hb_user_data_array_t user_data;
 
-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_MUTEX_INIT, HB_USER_DATA_ARRAY_INIT}
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
 
   static inline void *create (unsigned int size) {
     hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
 
     if (likely (obj))
       obj->init ();
 
     return obj;
   }
 
   inline void init (void) {
     ref_count.init (1);
-    mutex.init ();
     user_data.init ();
   }
 
   inline bool is_inert (void) const {
     return unlikely (ref_count.is_invalid ());
   }
 
   inline void reference (void) {
@@ -135,45 +132,36 @@ struct hb_object_header_t
 
   inline bool destroy (void) {
     if (unlikely (!this || this->is_inert ()))
       return false;
     if (ref_count.dec () != 1)
       return false;
 
     ref_count.finish (); /* Do this before user_data */
-    user_data.finish (mutex);
-    mutex.finish ();
+    user_data.finish ();
 
     return true;
   }
 
-  inline void lock (void) {
-    mutex.lock ();
-  }
-
-  inline void unlock (void) {
-    mutex.unlock ();
-  }
-
   inline bool set_user_data (hb_user_data_key_t *key,
 			     void *              data,
 			     hb_destroy_func_t   destroy_func,
 			     hb_bool_t           replace) {
     if (unlikely (!this || this->is_inert ()))
       return false;
 
-    return user_data.set (key, data, destroy_func, replace, mutex);
+    return user_data.set (key, data, destroy_func, replace);
   }
 
   inline void *get_user_data (hb_user_data_key_t *key) {
     if (unlikely (!this || this->is_inert ()))
       return NULL;
 
-    return user_data.get (key, mutex);
+    return user_data.get (key);
   }
 
   inline void trace (const char *function) const {
     if (unlikely (!this)) return;
     /* TODO We cannot use DEBUG_MSG_FUNC here since that one currently only
      * prints the class name and throws away the template info. */
     DEBUG_MSG (OBJECT, (void *) this,
 	       "%s refcount=%d",
@@ -214,28 +202,16 @@ static inline Type *hb_object_reference 
 }
 template <typename Type>
 static inline bool hb_object_destroy (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
   return obj->header.destroy ();
 }
 template <typename Type>
-static inline void hb_object_lock (Type *obj)
-{
-  hb_object_trace (obj, HB_FUNC);
-  return obj->header.lock ();
-}
-template <typename Type>
-static inline void hb_object_unlock (Type *obj)
-{
-  hb_object_trace (obj, HB_FUNC);
-  return obj->header.unlock ();
-}
-template <typename Type>
 static inline bool hb_object_set_user_data (Type               *obj,
 					    hb_user_data_key_t *key,
 					    void *              data,
 					    hb_destroy_func_t   destroy,
 					    hb_bool_t           replace)
 {
   return obj->header.set_user_data (key, data, destroy, replace);
 }
--- a/gfx/harfbuzz/src/hb-old.cc
+++ b/gfx/harfbuzz/src/hb-old.cc
@@ -95,52 +95,52 @@ hb_old_convertStringToGlyphIndices (HB_F
 
     if (rightToLeft)
       u = hb_unicode_funcs_get_default ()->mirroring (u);
 
     font->get_glyph (u, 0, &u); /* TODO Variation selectors */
 
     glyphs[i] = u;
   }
-  *numGlyphs = length; // XXX
+  *numGlyphs = length; /* XXX */
 
   return true;
 }
 
 static void
 hb_old_getGlyphAdvances (HB_Font old_font,
 			 const HB_Glyph *glyphs,
 			 hb_uint32 numGlyphs,
 			 HB_Fixed *advances,
-			 int flags /*HB_ShaperFlag*/)
+			 int flags /*HB_ShaperFlag*/ HB_UNUSED)
 {
   hb_font_t *font = (hb_font_t *) old_font->userData;
 
   for (unsigned int i = 0; i < numGlyphs; i++)
     advances[i] = font->get_glyph_h_advance (glyphs[i]);
 }
 
 static HB_Bool
 hb_old_canRender (HB_Font old_font,
 		  const HB_UChar16 *string,
 		  hb_uint32 length)
 {
-  return true; // TODO
+  return true; /* TODO */
 }
 
 static HB_Error
 hb_old_getPointInOutline (HB_Font old_font,
 			  HB_Glyph glyph,
 			  int flags /*HB_ShaperFlag*/,
 			  hb_uint32 point,
 			  HB_Fixed *xpos,
 			  HB_Fixed *ypos,
 			  hb_uint32 *nPoints)
 {
-  return HB_Err_Ok; // TODO
+  return HB_Err_Ok; /* TODO */
 }
 
 static void
 hb_old_getGlyphMetrics (HB_Font old_font,
 			HB_Glyph glyph,
 			HB_GlyphMetrics *metrics)
 {
   hb_font_t *font = (hb_font_t *) old_font->userData;
@@ -225,18 +225,18 @@ hb_old_shaper_font_data_t *
   if (unlikely (!data)) {
     DEBUG_MSG (OLD, font, "malloc()ing HB_Font failed");
     return NULL;
   }
 
   data->klass = &hb_old_font_class;
   data->x_ppem = font->x_ppem;
   data->y_ppem = font->y_ppem;
-  data->x_scale = font->x_scale; // XXX
-  data->y_scale = font->y_scale; // XXX
+  data->x_scale = font->x_scale; /* XXX */
+  data->y_scale = font->y_scale; /* XXX */
   data->userData = font;
 
   return data;
 }
 
 void
 _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data)
 {
@@ -246,35 +246,35 @@ void
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_old_shaper_shape_plan_data_t {};
 
 hb_old_shaper_shape_plan_data_t *
-_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
-				       const hb_feature_t *user_features,
-				       unsigned int        num_user_features)
+_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+				       const hb_feature_t *user_features HB_UNUSED,
+				       unsigned int        num_user_features HB_UNUSED)
 {
   return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
-_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data)
+_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data HB_UNUSED)
 {
 }
 
 
 /*
  * shaper
  */
 
 hb_bool_t
-_hb_old_shape (hb_shape_plan_t    *shape_plan,
+_hb_old_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
 	       hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   HB_Face old_face = HB_SHAPER_DATA_GET (face);
   HB_Font old_font = HB_SHAPER_DATA_GET (font);
@@ -364,17 +364,17 @@ retry:
   /* Calculate visual-clusters.  That's what we ship. */
   for (unsigned int i = 0; i < num_glyphs; i++)
     vis_clusters[i] = -1;
   for (unsigned int i = 0; i < buffer->len; i++) {
     uint32_t *p = &vis_clusters[item.log_clusters[buffer->info[i].utf16_index()]];
     *p = MIN (*p, buffer->info[i].cluster);
   }
   for (unsigned int i = 1; i < num_glyphs; i++)
-    if (vis_clusters[i] == -1)
+    if (vis_clusters[i] == (uint32_t) -1)
       vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
 
   buffer->ensure (num_glyphs);
   if (buffer->in_error)
     return false;
 
--- a/gfx/harfbuzz/src/hb-open-file-private.hh
+++ b/gfx/harfbuzz/src/hb-open-file-private.hh
@@ -49,17 +49,17 @@ namespace OT {
 struct OpenTypeFontFile;
 struct OffsetTable;
 struct TTCHeader;
 
 
 typedef struct TableRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   Tag		tag;		/* 4-byte identifier. */
   CheckSum	checkSum;	/* CheckSum for this table. */
   ULONG		offset;		/* Offset from beginning of TrueType font
 				 * file. */
   ULONG		length;		/* Length of this table. */
@@ -98,17 +98,17 @@ typedef struct OffsetTable
   {
     unsigned int table_index;
     find_table_index (tag, &table_index);
     return get_table (table_index);
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
   }
 
   protected:
   Tag		sfnt_version;	/* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
   USHORT	numTables;	/* Number of tables. */
   USHORT	searchRange;	/* (Maximum power of 2 <= numTables) x 16 */
   USHORT	entrySelector;	/* Log2(maximum power of 2 <= numTables). */
@@ -126,17 +126,17 @@ typedef struct OffsetTable
 struct TTCHeaderVersion1
 {
   friend struct TTCHeader;
 
   inline unsigned int get_face_count (void) const { return table.len; }
   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (table.sanitize (c, this));
   }
 
   protected:
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion	version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000 */
   LongOffsetLongArrayOf<OffsetTable>
@@ -165,17 +165,17 @@ struct TTCHeader
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
     case 1: return u.version1.get_face (i);
     default:return Null(OpenTypeFontFace);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
     case 1: return TRACE_RETURN (u.version1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
@@ -227,17 +227,17 @@ struct OpenTypeFontFile
     case Typ1Tag:
     case TrueTypeTag:	return u.fontFace;
     case TTCTag:	return u.ttcHeader.get_face (i);
     default:		return Null(OpenTypeFontFace);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
     switch (u.tag) {
     case CFFTag:	/* All the non-collection tags */
     case TrueTag:
     case Typ1Tag:
     case TrueTypeTag:	return TRACE_RETURN (u.fontFace.sanitize (c));
     case TTCTag:	return TRACE_RETURN (u.ttcHeader.sanitize (c));
     default:		return TRACE_RETURN (true);
@@ -250,12 +250,12 @@ struct OpenTypeFontFile
   OpenTypeFontFace	fontFace;
   TTCHeader		ttcHeader;
   } u;
   public:
   DEFINE_SIZE_UNION (4, tag);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OPEN_FILE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -32,16 +32,17 @@
 #include "hb-private.hh"
 
 #include "hb-blob.h"
 
 
 namespace OT {
 
 
+
 /*
  * Casts
  */
 
 /* Cast to struct T, reference to reference */
 template<typename Type, typename TObject>
 inline const Type& CastR(const TObject &X)
 { return reinterpret_cast<const Type&> (X); }
@@ -160,22 +161,32 @@ ASSERT_STATIC (Type::min_size + 1 <= siz
  * Sanitize
  */
 
 #ifndef HB_DEBUG_SANITIZE
 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
 #endif
 
 
-#define TRACE_SANITIZE() \
-	hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
+#define TRACE_SANITIZE(this) \
+	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
 
 
 struct hb_sanitize_context_t
 {
+  inline const char *get_name (void) { return "SANITIZE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
+  typedef bool return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.sanitize (this); }
+  static return_t default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
+
   inline void init (hb_blob_t *b)
   {
     this->blob = hb_blob_reference (b);
     this->writable = false;
   }
 
   inline void start_processing (void)
   {
@@ -200,53 +211,57 @@ struct hb_sanitize_context_t
     this->blob = NULL;
     this->start = this->end = NULL;
   }
 
   inline bool check_range (const void *base, unsigned int len) const
   {
     const char *p = (const char *) base;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "check_range [%p..%p] (%d bytes) in [%p..%p]",
-					      p, p + len, len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "check_range [%p..%p] (%d bytes) in [%p..%p]",
+       p, p + len, len,
+       this->start, this->end);
 
     return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
   }
 
   inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
   {
     const char *p = (const char *) base;
     bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
-					      p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
+       p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
+       this->start, this->end);
 
     return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
   }
 
   template <typename Type>
   inline bool check_struct (const Type *obj) const
   {
     return likely (this->check_range (obj, obj->min_size));
   }
 
   inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
   {
     const char *p = (const char *) base;
     this->edit_count++;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-					      "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-					      this->edit_count,
-					      p, p + len, len,
-					      this->start, this->end);
+    hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace
+      (&this->debug_depth, "SANITIZE", this->blob, NULL,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end,
+       this->writable ? "GRANTED" : "DENIED");
 
     return TRACE_RETURN (this->writable);
   }
 
   mutable unsigned int debug_depth;
   const char *start, *end;
   bool writable;
   unsigned int edit_count;
@@ -331,18 +346,20 @@ struct Sanitizer
  * Serialize
  */
 
 #ifndef HB_DEBUG_SERIALIZE
 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
 #endif
 
 
-#define TRACE_SERIALIZE() \
-	hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE", c, HB_FUNC, "");
+#define TRACE_SERIALIZE(this) \
+	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
+	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
+	 "");
 
 
 struct hb_serialize_context_t
 {
   inline hb_serialize_context_t (void *start, unsigned int size)
   {
     this->start = (char *) start;
     this->end = this->start + size;
@@ -513,55 +530,66 @@ struct BEInt<Type, 4>
 {
   public:
   inline void set (Type i) { hb_be_uint32_put (v,i); }
   inline operator Type (void) const { return hb_be_uint32_get (v); }
   inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
   inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
   private: uint8_t v[4];
 };
+template <typename Type>
+struct BEInt<Type, 3>
+{
+  public:
+  inline void set (Type i) { hb_be_uint24_put (v,i); }
+  inline operator Type (void) const { return hb_be_uint24_get (v); }
+  inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); }
+  inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
+  private: uint8_t v[3];
+};
 
 /* Integer types in big-endian order and no alignment requirement */
-template <typename Type>
+template <typename Type, unsigned int Size>
 struct IntType
 {
   inline void set (Type i) { v.set (i); }
   inline operator Type(void) const { return v; }
-  inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
-  inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
-  static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { return b->cmp (*a); }
-  inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
+  inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; }
+  inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; }
+  static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
   inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
   protected:
-  BEInt<Type, sizeof (Type)> v;
+  BEInt<Type, Size> v;
   public:
-  DEFINE_SIZE_STATIC (sizeof (Type));
+  DEFINE_SIZE_STATIC (Size);
 };
 
-typedef IntType<uint16_t> USHORT;	/* 16-bit unsigned integer. */
-typedef IntType<int16_t>  SHORT;	/* 16-bit signed integer. */
-typedef IntType<uint32_t> ULONG;	/* 32-bit unsigned integer. */
-typedef IntType<int32_t>  LONG;		/* 32-bit signed integer. */
+typedef IntType<uint16_t, 2> USHORT;	/* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> SHORT;	/* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> ULONG;	/* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> LONG;	/* 32-bit signed integer. */
+typedef IntType<uint32_t, 3> UINT24;	/* 24-bit unsigned integer. */
 
 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
 typedef SHORT FWORD;
 
 /* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
 typedef USHORT UFWORD;
 
 /* Date represented in number of seconds since 12:00 midnight, January 1,
  * 1904. The value is represented as a signed 64-bit integer. */
 struct LONGDATETIME
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
   private:
   LONG major;
   ULONG minor;
   public:
   DEFINE_SIZE_STATIC (8);
 };
@@ -615,17 +643,17 @@ struct CheckSum : ULONG
  * Version Numbers
  */
 
 struct FixedVersion
 {
   inline uint32_t to_int (void) const { return (major << 16) + minor; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   USHORT major;
   USHORT minor;
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -655,34 +683,40 @@ struct GenericOffsetTo : OffsetType
   inline Type& serialize (hb_serialize_context_t *c, void *base)
   {
     Type *t = c->start_embed<Type> ();
     this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
     return *t;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
     Type &obj = StructAtOffset<Type> (base, offset);
     return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
     Type &obj = StructAtOffset<Type> (base, offset);
     return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
   }
 
-  private:
+  inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) {
+    if (c->may_edit (this, this->static_size)) {
+      this->set (v);
+      return true;
+    }
+    return false;
+  }
   /* Set the offset to Null */
   inline bool neuter (hb_sanitize_context_t *c) {
     if (c->may_edit (this, this->static_size)) {
       this->set (0); /* 0 is Null offset */
       return true;
     }
     return false;
   }
@@ -728,73 +762,73 @@ struct GenericArrayOf
     return array[i];
   }
   inline unsigned int get_size (void) const
   { return len.static_size + len * Type::static_size; }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
     if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<Type> &items,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < items_len; i++)
       array[i] = items[i];
     items.advance (items_len);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
      * we do not need to call their sanitize() as we already did
      * a bound check on the aggregate array size.  We just include
      * a small unreachable expression to make sure the structs
      * pointed to do have a simple sanitize(), ie. they do not
      * reference other structs via offsets.
      */
     (void) (false && array[0].sanitize (c));
 
     return TRACE_RETURN (true);
   }
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!array[i].sanitize (c, base)))
         return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!array[i].sanitize (c, base, user_data)))
         return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
   }
 
   public:
   LenType len;
   Type array[VAR];
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
@@ -826,22 +860,22 @@ struct OffsetListOf : OffsetArrayOf<Type
 {
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= this->len)) return Null(Type);
     return this+this->array[i];
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
   }
   template <typename T>
   inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
 
 /* An array with a USHORT number of elements,
  * starting at second element. */
 template <typename Type>
@@ -854,34 +888,34 @@ struct HeadlessArrayOf
   }
   inline unsigned int get_size (void) const
   { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<Type> &items,
 			 unsigned int items_len)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     len.set (items_len); /* TODO(serialize) Overflow? */
     if (unlikely (!items_len)) return TRACE_RETURN (true);
     if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < items_len - 1; i++)
       array[i] = items[i];
     items.advance (items_len - 1);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize_shallow (hb_sanitize_context_t *c) {
     return c->check_struct (this)
 	&& c->check_array (this, Type::static_size, len);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
      * we do not need to call their sanitize() as we already did
      * a bound check on the aggregate array size.  We just include
      * a small unreachable expression to make sure the structs
      * pointed to do have a simple sanitize(), ie. they do not
      * reference other structs via offsets.
@@ -917,12 +951,12 @@ struct SortedArrayOf : ArrayOf<Type> {
       };
       const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
       return p ? p - this->array : -1;
     }
   }
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OPEN_TYPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-head-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
@@ -47,17 +47,17 @@ struct head
 
   inline unsigned int get_upem (void) const {
     unsigned int upem = unitsPerEm;
     /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
   protected:
   FixedVersion	version;		/* Version of the head table--currently
 					 * 0x00010000 for version 1.0. */
   FixedVersion	fontRevision;		/* Set by font manufacturer. */
   ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
@@ -138,12 +138,12 @@ struct head
 					 * -2: Like -1 but also contains neutrals. */
   SHORT		indexToLocFormat;	/* 0 for short offsets, 1 for long. */
   SHORT		glyphDataFormat;	/* 0 for current format. */
   public:
   DEFINE_SIZE_STATIC (54);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_HEAD_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-hhea-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hhea-table.hh
@@ -40,17 +40,17 @@ namespace OT {
 #define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
 
 
 struct hhea
 {
   static const hb_tag_t Tag	= HB_OT_TAG_hhea;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
   protected:
   FixedVersion	version;		/* 0x00010000 for version 1.0. */
   FWORD		ascender;		/* Typographic ascent. <a
 					 * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
 					 * (Distance from baseline of highest
@@ -86,12 +86,12 @@ struct hhea
   SHORT		metricDataFormat;	/* 0 for current format. */
   USHORT	numberOfHMetrics;	/* Number of hMetric entries in 'hmtx'
 					 * table */
   public:
   DEFINE_SIZE_STATIC (36);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_HHEA_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -48,17 +48,17 @@ struct LongHorMetric
   DEFINE_SIZE_STATIC (4);
 };
 
 struct hmtx
 {
   static const hb_tag_t Tag	= HB_OT_TAG_hmtx;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return TRACE_RETURN (true);
   }
 
   protected:
   LongHorMetric	longHorMetric[VAR];	/* Paired advance width and left side
 					 * bearing values for each glyph. The
@@ -81,12 +81,12 @@ struct hmtx
 					 * the end. This allows a monospaced
 					 * font to vary the left side bearing
 					 * values for each glyph. */
   public:
   DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_HMTX_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -55,19 +55,24 @@ namespace OT {
 
 template <typename Type>
 struct Record
 {
   inline int cmp (hb_tag_t a) const {
     return tag.cmp (a);
   }
 
+  struct sanitize_closure_t {
+    hb_tag_t tag;
+    void *list_base;
+  };
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base));
+    TRACE_SANITIZE (this);
+    const sanitize_closure_t closure = {tag, base};
+    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
   }
 
   Tag		tag;		/* 4-byte Tag identifier */
   OffsetTo<Type>
 		offset;		/* Offset from beginning of object holding
 				 * the Record */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -110,31 +115,31 @@ struct RecordArrayOf : SortedArrayOf<Rec
 
 template <typename Type>
 struct RecordListOf : RecordArrayOf<Type>
 {
   inline const Type& operator [] (unsigned int i) const
   { return this+RecordArrayOf<Type>::operator [](i).offset; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
   }
 };
 
 
 struct RangeRecord
 {
   inline int cmp (hb_codepoint_t g) const {
     hb_codepoint_t a = start, b = end;
     return g < a ? -1 : g <= b ? 0 : +1 ;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   inline bool intersects (const hb_set_t *glyphs) const {
     return glyphs->intersects (start, end);
   }
 
   template <typename set_t>
@@ -187,18 +192,19 @@ struct LangSys
   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
   inline unsigned int get_required_feature_index (void) const
   {
     if (reqFeatureIndex == 0xffff)
       return Index::NOT_FOUND_INDEX;
    return reqFeatureIndex;;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c,
+			const Record<LangSys>::sanitize_closure_t * = NULL) {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
   Offset	lookupOrder;	/* = Null (reserved for an offset to a
 				 * reordering table) */
   USHORT	reqFeatureIndex;/* Index of a feature required for this
 				 * language system--if no required features
 				 * = 0xFFFF */
@@ -225,18 +231,19 @@ struct Script
     return this+langSys[i].offset;
   }
   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
   { return langSys.find_index (tag, index); }
 
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c,
+			const Record<Script>::sanitize_closure_t * = NULL) {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
   }
 
   protected:
   OffsetTo<LangSys>
 		defaultLangSys;	/* Offset to DefaultLangSys table--from
 				 * beginning of Script table--may be Null */
   RecordArrayOf<LangSys>
@@ -244,33 +251,288 @@ struct Script
 				 * alphabetically by LangSysTag */
   public:
   DEFINE_SIZE_ARRAY (4, langSys);
 };
 
 typedef RecordListOf<Script> ScriptList;
 
 
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+struct FeatureParamsSize
+{
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+
+    /* This subtable has some "history", if you will.  Some earlier versions of
+     * Adobe tools calculated the offset of the FeatureParams sutable from the
+     * beginning of the FeatureList table!  Now, that is dealt with in the
+     * Feature implementation.  But we still need to be able to tell junk from
+     * real data.  Note: We don't check that the nameID actually exists.
+     *
+     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
+     *
+     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
+     * coming out soon, and that the makeotf program will build a font with a
+     * 'size' feature that is correct by the specification.
+     *
+     * The specification for this feature tag is in the "OpenType Layout Tag
+     * Registry". You can see a copy of this at:
+     * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
+     *
+     * Here is one set of rules to determine if the 'size' feature is built
+     * correctly, or as by the older versions of MakeOTF. You may be able to do
+     * better.
+     *
+     * Assume that the offset to the size feature is according to specification,
+     * and make the following value checks. If it fails, assume the the size
+     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
+     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
+     * offset from the beginning of the FeatureList table, rather than from the
+     * beginning of the 'size' Feature table.
+     *
+     * If "design size" == 0:
+     *     fails check
+     *
+     * Else if ("subfamily identifier" == 0 and
+     *     "range start" == 0 and
+     *     "range end" == 0 and
+     *     "range start" == 0 and
+     *     "menu name ID" == 0)
+     *     passes check: this is the format used when there is a design size
+     * specified, but there is no recommended size range.
+     *
+     * Else if ("design size" <  "range start" or
+     *     "design size" >   "range end" or
+     *     "range end" <= "range start" or
+     *     "menu name ID"  < 256 or
+     *     "menu name ID"  > 32767 or
+     *     menu name ID is not a name ID which is actually in the name table)
+     *     fails test
+     * Else
+     *     passes test.
+     */
+
+    if (!designSize)
+      return TRACE_RETURN (false);
+    else if (subfamilyID == 0 &&
+	     subfamilyNameID == 0 &&
+	     rangeStart == 0 &&
+	     rangeEnd == 0)
+      return TRACE_RETURN (true);
+    else if (designSize < rangeStart ||
+	     designSize > rangeEnd ||
+	     subfamilyNameID < 256 ||
+	     subfamilyNameID > 32767)
+      return TRACE_RETURN (false);
+    else
+      return TRACE_RETURN (true);
+  }
+
+  USHORT	designSize;	/* Represents the design size in 720/inch
+				 * units (decipoints).  The design size entry
+				 * must be non-zero.  When there is a design
+				 * size but no recommended size range, the
+				 * rest of the array will consist of zeros. */
+  USHORT	subfamilyID;	/* Has no independent meaning, but serves
+				 * as an identifier that associates fonts
+				 * in a subfamily. All fonts which share a
+				 * Preferred or Font Family name and which
+				 * differ only by size range shall have the
+				 * same subfamily value, and no fonts which
+				 * differ in weight or style shall have the
+				 * same subfamily value. If this value is
+				 * zero, the remaining fields in the array
+				 * will be ignored. */
+  USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
+				 * value must be set in the range 256 - 32767
+				 * (inclusive). It records the value of a
+				 * field in the name table, which must
+				 * contain English-language strings encoded
+				 * in Windows Unicode and Macintosh Roman,
+				 * and may contain additional strings
+				 * localized to other scripts and languages.
+				 * Each of these strings is the name an
+				 * application should use, in combination
+				 * with the family name, to represent the
+				 * subfamily in a menu.  Applications will
+				 * choose the appropriate version based on
+				 * their selection criteria. */
+  USHORT	rangeStart;	/* Large end of the recommended usage range
+				 * (inclusive), stored in 720/inch units
+				 * (decipoints). */
+  USHORT	rangeEnd;	/* Small end of the recommended usage range
+				   (exclusive), stored in 720/inch units
+				 * (decipoints). */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
+struct FeatureParamsStylisticSet
+{
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    /* Right now minorVersion is at zero.  Which means, any table supports
+     * the uiNameID field. */
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  USHORT	minorVersion;	/* (set to 0): This corresponds to a “minor”
+				 * version number. Additional data may be
+				 * added to the end of this Feature Parameters
+				 * table in the future. */
+
+  USHORT	uiNameID;	/* The 'name' table name ID that specifies a
+				 * string (or strings, for multiple languages)
+				 * for a user-interface label for this
+				 * feature.  The values of uiLabelNameId and
+				 * sampleTextNameId are expected to be in the
+				 * font-specific name ID range (256-32767),
+				 * though that is not a requirement in this
+				 * Feature Parameters specification. The
+				 * user-interface label for the feature can
+				 * be provided in multiple languages. An
+				 * English string should be included as a
+				 * fallback. The string should be kept to a
+				 * minimal length to fit comfortably with
+				 * different application interfaces. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct FeatureParamsCharacterVariants
+{
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+			 characters.sanitize (c));
+  }
+
+  USHORT	format;			/* Format number is set to 0. */
+  USHORT	featUILableNameID;	/* The ‘name’ table name ID that
+					 * specifies a string (or strings,
+					 * for multiple languages) for a
+					 * user-interface label for this
+					 * feature. (May be NULL.) */
+  USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
+					 * specifies a string (or strings,
+					 * for multiple languages) that an
+					 * application can use for tooltip
+					 * text for this feature. (May be
+					 * NULL.) */
+  USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
+					 * specifies sample text that
+					 * illustrates the effect of this
+					 * feature. (May be NULL.) */
+  USHORT	numNamedParameters;	/* Number of named parameters. (May
+					 * be zero.) */
+  USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
+					 * used to specify strings for
+					 * user-interface labels for the
+					 * feature parameters. (Must be zero
+					 * if numParameters is zero.) */
+  ArrayOf<UINT24>
+		characters;		/* Array of the Unicode Scalar Value
+					 * of the characters for which this
+					 * feature provides glyph variants.
+					 * (May be zero.) */
+  public:
+  DEFINE_SIZE_ARRAY (14, characters);
+};
+
+struct FeatureParams
+{
+  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
+    TRACE_SANITIZE (this);
+    if (tag == HB_TAG ('s','i','z','e'))
+      return TRACE_RETURN (u.size.sanitize (c));
+    if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return TRACE_RETURN (u.stylisticSet.sanitize (c));
+    if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return TRACE_RETURN (u.characterVariants.sanitize (c));
+    return TRACE_RETURN (true);
+  }
+
+  inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
+  {
+    if (tag == HB_TAG ('s','i','z','e'))
+      return u.size;
+    return Null(FeatureParamsSize);
+  }
+
+  private:
+  union {
+  FeatureParamsSize			size;
+  FeatureParamsStylisticSet		stylisticSet;
+  FeatureParamsCharacterVariants	characterVariants;
+  } u;
+  DEFINE_SIZE_STATIC (17);
+};
+
 struct Feature
 {
   inline unsigned int get_lookup_count (void) const
   { return lookupIndex.len; }
   inline hb_tag_t get_lookup_index (unsigned int i) const
   { return lookupIndex[i]; }
   inline unsigned int get_lookup_indexes (unsigned int start_index,
 					  unsigned int *lookup_count /* IN/OUT */,
 					  unsigned int *lookup_tags /* OUT */) const
   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c));
+  inline const FeatureParams &get_feature_params (void) const
+  { return this+featureParams; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+			const Record<Feature>::sanitize_closure_t *closure) {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+      return TRACE_RETURN (false);
+
+    /* Some earlier versions of Adobe tools calculated the offset of the
+     * FeatureParams subtable from the beginning of the FeatureList table!
+     *
+     * If sanitizing "failed" for the FeatureParams subtable, try it with the
+     * alternative location.  We would know sanitize "failed" if old value
+     * of the offset was non-zero, but it's zeroed now.
+     *
+     * Only do this for the 'size' feature, since at the time of the faulty
+     * Adobe tools, only the 'size' feature had FeatureParams defined.
+     */
+
+    Offset orig_offset = featureParams;
+    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+      return TRACE_RETURN (false);
+
+    if (likely (!orig_offset))
+      return TRACE_RETURN (true);
+
+    if (featureParams == 0 && closure &&
+	closure->tag == HB_TAG ('s','i','z','e') &&
+	closure->list_base && closure->list_base < this)
+    {
+      unsigned int new_offset_int = (unsigned int) orig_offset -
+				    ((char *) this - (char *) closure->list_base);
+
+      Offset new_offset;
+      /* Check that it did not overflow. */
+      new_offset.set (new_offset_int);
+      if (new_offset == new_offset_int &&
+	  featureParams.try_set (c, new_offset) &&
+	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+	return TRACE_RETURN (false);
+    }
+
+    return TRACE_RETURN (true);
   }
 
-  Offset	featureParams;	/* Offset to Feature Parameters table (if one
+  OffsetTo<FeatureParams>
+		 featureParams;	/* Offset to Feature Parameters table (if one
 				 * has been defined for the feature), relative
 				 * to the beginning of the Feature Table; = Null
 				 * if not required */
   IndexArray	 lookupIndex;	/* Array of LookupList indices */
   public:
   DEFINE_SIZE_ARRAY (4, lookupIndex);
 };
 
@@ -313,31 +575,31 @@ struct Lookup
     return flag;
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 unsigned int lookup_type,
 			 uint32_t lookup_props,
 			 unsigned int num_subtables)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     lookupType.set (lookup_type);
     lookupFlag.set (lookup_props & 0xFFFF);
     if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       markFilteringSet.set (lookup_props >> 16);
     }
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
     }
     return TRACE_RETURN (true);
@@ -372,28 +634,28 @@ struct CoverageFormat1
     ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
     return i;
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     glyphArray.len.set (num_glyphs);
     if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       glyphArray[i] = glyphs[i];
     glyphs.advance (num_glyphs);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (glyphArray.sanitize (c));
   }
 
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
     return glyphs->has (glyphArray[index]);
   }
 
   template <typename set_t>
@@ -440,17 +702,17 @@ struct CoverageFormat2
     }
     return NOT_COVERED;
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
 
     if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
 
     unsigned int num_ranges = 1;
     for (unsigned int i = 1; i < num_glyphs; i++)
       if (glyphs[i - 1] + 1 != glyphs[i])
         num_ranges++;
@@ -469,17 +731,17 @@ struct CoverageFormat2
       } else {
         rangeRecord[range].end = glyphs[i];
       }
     glyphs.advance (num_glyphs);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
     unsigned int i;
     unsigned int count = rangeRecord.len;
     for (i = 0; i < count; i++) {
       const RangeRecord &range = rangeRecord[i];
@@ -536,47 +798,45 @@ struct CoverageFormat2
 				 * Start GlyphID. rangeCount entries
 				 * long */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct Coverage
 {
-  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
-
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
     case 1: return u.format1.get_coverage(glyph_id);
     case 2: return u.format2.get_coverage(glyph_id);
     default:return NOT_COVERED;
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     unsigned int num_ranges = 1;
     for (unsigned int i = 1; i < num_glyphs; i++)
       if (glyphs[i - 1] + 1 != glyphs[i])
         num_ranges++;
     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
     case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
     default:return TRACE_RETURN (false);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
@@ -677,20 +937,28 @@ struct ClassDefFormat1
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
       return classValue[glyph_id - startGlyph];
     return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
   }
 
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = classValue.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (classValue[i] == klass)
+        glyphs->add (startGlyph + i);
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = classValue.len;
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
         return true;
     return false;
   }
 
@@ -712,20 +980,28 @@ struct ClassDefFormat2
   {
     int i = rangeRecord.search (glyph_id);
     if (i != -1)
       return rangeRecord[i].value;
     return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].value == klass)
+        rangeRecord[i].add_coverage (glyphs);
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
         return true;
     return false;
   }
 
@@ -735,37 +1011,43 @@ struct ClassDefFormat2
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct ClassDef
 {
-  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
-
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
     case 1: return u.format1.get_class(glyph_id);
     case 2: return u.format2.get_class(glyph_id);
     default:return 0;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
+  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
+    switch (u.format) {
+    case 1: u.format1.add_class (glyphs, klass); return;
+    case 2: u.format2.add_class (glyphs, klass); return;
+    default:return;
+    }
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
     case 2: return u.format2.intersects_class (glyphs, klass);
     default:return false;
     }
   }
 
@@ -831,17 +1113,17 @@ struct Device
   inline unsigned int get_size (void) const
   {
     unsigned int f = deltaFormat;
     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
   protected:
   USHORT	startSize;		/* Smallest size to correct--in ppem */
   USHORT	endSize;		/* Largest size to correct--in ppem */
   USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
 					 * 1	Signed 2-bit value, 8 values per uint16
@@ -849,12 +1131,12 @@ struct Device
 					 * 3	Signed 8-bit value, 2 values per uint16
 					 */
   USHORT	deltaValue[VAR];	/* Array of compressed data */
   public:
   DEFINE_SIZE_ARRAY (6, deltaValue);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -46,17 +46,17 @@ typedef ArrayOf<USHORT> AttachPoint;	/* 
 
 struct AttachList
 {
   inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
 					 unsigned int start_offset,
 					 unsigned int *point_count /* IN/OUT */,
 					 unsigned int *point_array /* OUT */) const
   {
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (index == NOT_COVERED)
     {
       if (point_count)
 	*point_count = 0;
       return 0;
     }
 
     const AttachPoint &points = this+attachPoint[index];
@@ -67,17 +67,17 @@ struct AttachList
       for (unsigned int i = 0; i < count; i++)
 	point_array[i] = array[i];
     }
 
     return points.len;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
   }
 
   protected:
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table -- from
 					 * beginning of AttachList table */
   OffsetArrayOf<AttachPoint>
@@ -97,17 +97,17 @@ struct CaretValueFormat1
 
   private:
   inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
   USHORT	caretValueFormat;	/* Format identifier--format = 1 */
   SHORT		coordinate;		/* X or Y value, in design units */
   public:
   DEFINE_SIZE_STATIC (4);
@@ -123,17 +123,17 @@ struct CaretValueFormat2
     hb_position_t x, y;
     if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y))
       return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
     else
       return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
   USHORT	caretValueFormat;	/* Format identifier--format = 2 */
   USHORT	caretValuePoint;	/* Contour point index on glyph */
   public:
   DEFINE_SIZE_STATIC (4);
@@ -146,17 +146,17 @@ struct CaretValueFormat3
   inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
   {
     return HB_DIRECTION_IS_HORIZONTAL (direction) ?
            font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) :
            font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
   protected:
   USHORT	caretValueFormat;	/* Format identifier--format = 3 */
   SHORT		coordinate;		/* X or Y value, in design units */
   OffsetTo<Device>
 		deviceTable;		/* Offset to Device table for X or Y
@@ -174,17 +174,17 @@ struct CaretValue
     case 1: return u.format1.get_caret_value (font, direction, glyph_id);
     case 2: return u.format2.get_caret_value (font, direction, glyph_id);
     case 3: return u.format3.get_caret_value (font, direction, glyph_id);
     default:return 0;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     case 3: return TRACE_RETURN (u.format3.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
@@ -215,17 +215,17 @@ struct LigGlyph
       for (unsigned int i = 0; i < count; i++)
 	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id);
     }
 
     return carets.len;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (carets.sanitize (c, this));
   }
 
   protected:
   OffsetArrayOf<CaretValue>
 		carets;			/* Offset array of CaretValue tables
 					 * --from beginning of LigGlyph table
 					 * --in increasing coordinate order */
@@ -237,29 +237,29 @@ struct LigCaretList
 {
   inline unsigned int get_lig_carets (hb_font_t *font,
 				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      hb_position_t *caret_array /* OUT */) const
   {
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (index == NOT_COVERED)
     {
       if (caret_count)
 	*caret_count = 0;
       return 0;
     }
     const LigGlyph &lig_glyph = this+ligGlyph[index];
     return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
   }
 
   protected:
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of LigCaretList table */
   OffsetArrayOf<LigGlyph>
@@ -271,17 +271,17 @@ struct LigCaretList
 
 
 struct MarkGlyphSetsFormat1
 {
   inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   LongOffsetArrayOf<Coverage>
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
@@ -295,17 +295,17 @@ struct MarkGlyphSets
   {
     switch (u.format) {
     case 1: return u.format1.covers (set_index, glyph_id);
     default:return false;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -332,16 +332,18 @@ struct GDEF
     LigatureGlyph	= 2,
     MarkGlyph		= 3,
     ComponentGlyph	= 4
   };
 
   inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
   inline unsigned int get_glyph_class (hb_codepoint_t glyph) const
   { return (this+glyphClassDef).get_class (glyph); }
+  inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+  { (this+glyphClassDef).add_class (glyphs, klass); }
 
   inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; }
   inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
   { return (this+markAttachClassDef).get_class (glyph); }
 
   inline bool has_attach_points (void) const { return attachList != 0; }
   inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
 					 unsigned int start_offset,
@@ -358,17 +360,17 @@ struct GDEF
 				      hb_position_t *caret_array /* OUT */) const
   { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
 
   inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002 && markGlyphSetsDef[0] != 0; }
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (version.sanitize (c) &&
 			 likely (version.major == 1) &&
 			 glyphClassDef.sanitize (c, this) &&
 			 attachList.sanitize (c, this) &&
 			 ligCaretList.sanitize (c, this) &&
 			 markAttachClassDef.sanitize (c, this) &&
 			 (version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)));
   }
@@ -378,23 +380,23 @@ struct GDEF
    * 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);
 
     switch (klass) {
     default:
-    case UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
-    case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
-    case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
-    case ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
+    case UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED;
+    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_CLASS_MARK | (klass << 8);
+	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
     }
   }
 
 
   protected:
   FixedVersion	version;		/* Version of the GDEF table--currently
 					 * 0x00010002 */
   OffsetTo<ClassDef>
@@ -418,12 +420,12 @@ struct GDEF
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 00010002. */
   public:
   DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -167,22 +167,22 @@ struct ValueFormat : USHORT
   public:
 
   inline bool has_device (void) const {
     unsigned int format = *this;
     return (format & devices) != 0;
   }
 
   inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   }
 
   inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     unsigned int len = get_len ();
 
     if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
 
     if (!has_device ()) return TRACE_RETURN (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
@@ -190,108 +190,99 @@ struct ValueFormat : USHORT
       values += len;
     }
 
     return TRACE_RETURN (true);
   }
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
   inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
 
     if (!has_device ()) return TRACE_RETURN (true);
 
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
         return TRACE_RETURN (false);
       values += stride;
     }
 
     return TRACE_RETURN (true);
   }
 };
 
 
 struct AnchorFormat1
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
       *x = font->em_scale_x (xCoordinate);
       *y = font->em_scale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   SHORT		xCoordinate;		/* Horizontal value--in design units */
   SHORT		yCoordinate;		/* Vertical value--in design units */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct AnchorFormat2
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
   {
       unsigned int x_ppem = font->x_ppem;
       unsigned int y_ppem = font->y_ppem;
       hb_position_t cx, cy;
       hb_bool_t ret = false;
 
       if (x_ppem || y_ppem)
 	ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
       *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
       *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 2 */
   SHORT		xCoordinate;		/* Horizontal value--in design units */
   SHORT		yCoordinate;		/* Vertical value--in design units */
   USHORT	anchorPoint;		/* Index to glyph contour point */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct AnchorFormat3
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
 			  hb_position_t *x, hb_position_t *y) const
   {
       *x = font->em_scale_x (xCoordinate);
       *y = font->em_scale_y (yCoordinate);
 
       if (font->x_ppem)
 	*x += (this+xDeviceTable).get_x_delta (font);
       if (font->y_ppem)
 	*y += (this+yDeviceTable).get_x_delta (font);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 3 */
   SHORT		xCoordinate;		/* Horizontal value--in design units */
   SHORT		yCoordinate;		/* Vertical value--in design units */
   OffsetTo<Device>
@@ -316,17 +307,17 @@ struct Anchor
     case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
     case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
     case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
     default:						 return;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     case 3: return TRACE_RETURN (u.format3.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
@@ -346,17 +337,17 @@ struct Anchor
 struct AnchorMatrix
 {
   inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
     return this+matrix[row * cols + col];
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
     unsigned int count = rows * cols;
     if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < count; i++)
       if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
@@ -371,17 +362,17 @@ struct AnchorMatrix
 };
 
 
 struct MarkRecord
 {
   friend struct MarkArray;
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
   protected:
   USHORT	klass;			/* Class defined for this mark */
   OffsetTo<Anchor>
 		markAnchor;		/* Offset to Anchor table--from
 					 * beginning of MarkArray table */
@@ -391,17 +382,17 @@ 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 ();
+    TRACE_APPLY (this);
     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
     const Anchor& mark_anchor = this + record.markAnchor;
     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
@@ -413,50 +404,52 @@ struct MarkArray : ArrayOf<MarkRecord>	/
     o.y_offset = base_y - mark_y;
     o.attach_lookback() = c->buffer->idx - glyph_pos;
 
     c->buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
 
 
 /* Lookups */
 
 struct SinglePosFormat1
 {
-  friend struct SinglePos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage  (c->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());
 
     c->buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -466,43 +459,45 @@ struct SinglePosFormat1
 					 * value(s)--applied to all glyphs in
 					 * the Coverage table */
   public:
   DEFINE_SIZE_ARRAY (6, values);
 };
 
 struct SinglePosFormat2
 {
-  friend struct SinglePos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage  (c->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());
 
     c->buffer->idx++;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -512,41 +507,29 @@ struct SinglePosFormat2
   ValueRecord	values;			/* Array of ValueRecords--positioning
 					 * values applied to glyphs */
   public:
   DEFINE_SIZE_ARRAY (8, values);
 };
 
 struct SinglePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
@@ -572,27 +555,44 @@ struct PairValueRecord
   public:
   DEFINE_SIZE_ARRAY (2, values);
 };
 
 struct PairSet
 {
   friend struct PairPosFormat1;
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
+			      const ValueFormat *valueFormats) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    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++)
+    {
+      c->input->add (record->secondGlyph);
+      record = &StructAtOffset<PairValueRecord> (record, record_size);
+    }
+  }
+
   inline bool apply (hb_apply_context_t *c,
 		     const ValueFormat *valueFormats,
 		     unsigned int pos) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     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;
-    const PairValueRecord *record = CastP<PairValueRecord> (array);
     for (unsigned int i = 0; i < count; i++)
     {
       if (c->buffer->info[pos].codepoint == record->secondGlyph)
       {
 	valueFormats[0].apply_value (c->font, c->direction, this,
 				     &record->values[0], c->buffer->cur_pos());
 	valueFormats[1].apply_value (c->font, c->direction, this,
 				     &record->values[len1], c->buffer->pos[pos]);
@@ -610,17 +610,17 @@ struct PairSet
   struct sanitize_closure_t {
     void *base;
     ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
   };
 
   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
 
     unsigned int count = len;
     PairValueRecord *record = CastP<PairValueRecord> (array);
     return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
 		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
@@ -630,41 +630,46 @@ struct PairSet
   USHORT	array[VAR];		/* Array of PairValueRecords--ordered
 					 * by GlyphID of the second glyph */
   public:
   DEFINE_SIZE_ARRAY (2, array);
 };
 
 struct PairPosFormat1
 {
-  friend struct PairPos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage  (c->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) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     PairSet::sanitize_closure_t closure = {
       this,
       &valueFormat1,
       len1,
       1 + len1 + len2
@@ -688,59 +693,73 @@ struct PairPosFormat1
 		pairSet;		/* Array of PairSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (10, pairSet);
 };
 
 struct PairPosFormat2
 {
-  friend struct PairPos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    /* (this+coverage).add_coverage (c->input); // Don't need this. */
+
+    /* TODO only add values for pairs that have nonzero adjustments. */
 
-  private:
+    unsigned int count1 = class1Count;
+    const ClassDef &klass1 = this+classDef1;
+    for (unsigned int i = 0; i < count1; i++)
+      klass1.add_class (c->input, i);
+
+    unsigned int count2 = class2Count;
+    const ClassDef &klass2 = this+classDef2;
+    for (unsigned int i = 0; i < count2; i++)
+      klass2.add_class (c->input, i);
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage  (c->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) (c->buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
+    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);
     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());
     valueFormat2.apply_value (c->font, c->direction, this,
 			      v + len1, c->buffer->pos[skippy_iter.idx]);
 
     c->buffer->idx = skippy_iter.idx;
     if (len2)
       c->buffer->idx++;
 
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
        && classDef1.sanitize (c, this)
        && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int stride = len1 + len2;
@@ -778,41 +797,29 @@ struct PairPosFormat2
 					 * class1-major, class2-minor,
 					 * Each entry has value1 and value2 */
   public:
   DEFINE_SIZE_ARRAY (16, values);
 };
 
 struct PairPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
@@ -825,17 +832,17 @@ struct PairPos
 };
 
 
 struct EntryExitRecord
 {
   friend struct CursivePosFormat1;
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
   protected:
   OffsetTo<Anchor>
 		entryAnchor;		/* Offset to EntryAnchor table--from
 					 * beginning of CursivePos
 					 * subtable--may be NULL */
@@ -844,41 +851,43 @@ struct EntryExitRecord
 					 * beginning of CursivePos
 					 * subtable--may be NULL */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CursivePosFormat1
 {
-  friend struct CursivePos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
 
     /* We don't handle mark glyphs here. */
-    if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false);
+    if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
 
     hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
 
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)];
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (c->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) (c->buffer->info[skippy_iter.idx].codepoint)];
+    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint)];
     if (!next_record.entryAnchor) return TRACE_RETURN (false);
 
     unsigned int i = c->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);
@@ -936,17 +945,17 @@ struct CursivePosFormat1
 	pos[j].x_offset = exit_x - entry_x;
     }
 
     c->buffer->idx = j;
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of subtable */
@@ -954,39 +963,28 @@ struct CursivePosFormat1
 		entryExitRecord;	/* Array of EntryExit records--in
 					 * Coverage Index order */
   public:
   DEFINE_SIZE_ARRAY (6, entryExitRecord);
 };
 
 struct CursivePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -999,52 +997,56 @@ struct CursivePos
 
 typedef AnchorMatrix BaseArray;		/* base-major--
 					 * in order of BaseCoverage Index--,
 					 * mark-minor--
 					 * ordered by class--zero-based. */
 
 struct MarkBasePosFormat1
 {
-  friend struct MarkBasePos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+baseCoverage).add_coverage (c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
     unsigned int property;
     hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     do {
       if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) 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;
       skippy_iter.reject ();
     } while (1);
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
+    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
 
-    unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
+    unsigned int base_index = (this+baseCoverage).get_coverage  (c->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 ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
 			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to MarkCoverage table--from
@@ -1060,39 +1062,28 @@ struct MarkBasePosFormat1
 		baseArray;		/* Offset to BaseArray table--from
 					 * beginning of MarkBasePos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct MarkBasePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -1110,41 +1101,45 @@ typedef AnchorMatrix LigatureAttach;	/* 
 
 typedef OffsetListOf<LigatureAttach> LigatureArray;
 					/* Array of LigatureAttach
 					 * tables ordered by
 					 * LigatureCoverage Index */
 
 struct MarkLigPosFormat1
 {
-  friend struct MarkLigPos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+ligatureCoverage).add_coverage (c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
     unsigned int property;
     hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
+    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
 
     unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (c->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);
@@ -1161,17 +1156,17 @@ struct MarkLigPosFormat1
       comp_index = MIN (comp_count, get_lig_comp (c->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 ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
 			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		markCoverage;		/* Offset to Mark Coverage table--from
@@ -1188,39 +1183,28 @@ struct MarkLigPosFormat1
 		ligatureArray;		/* Offset to LigatureArray table--from
 					 * beginning of MarkLigPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct MarkLigPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -1233,37 +1217,41 @@ struct MarkLigPos
 
 typedef AnchorMatrix Mark2Array;	/* mark2-major--
 					 * in order of Mark2Coverage Index--,
 					 * mark1-minor--
 					 * ordered by class--zero-based. */
 
 struct MarkMarkPosFormat1
 {
-  friend struct MarkMarkPos;
-
-  private:
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+mark1Coverage).add_coverage (c->input);
+    (this+mark2Coverage).add_coverage (c->input);
+    /* TODO only add combinations that have nonzero adjustment. */
+  }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (c->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 */
     unsigned int property;
     hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
     if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
 
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false);
+    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 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]);
 
@@ -1278,24 +1266,24 @@ 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) (c->buffer->info[j].codepoint);
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (c->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 ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
 			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
 			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
@@ -1314,98 +1302,50 @@ struct MarkMarkPosFormat1
 		mark2Array;		/* Offset to Mark2Array table--from
 					 * beginning of MarkMarkPos subtable */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct MarkMarkPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-
-  inline const Coverage &get_coverage (void) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
   union {
   USHORT		format;		/* Format identifier */
   MarkMarkPosFormat1	format1;
   } u;
 };
 
 
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-
-struct ContextPos : Context
-{
-  friend struct PosLookupSubTable;
+struct ContextPos : Context {};
 
-  private:
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, position_lookup));
-  }
-};
-
-struct ChainContextPos : ChainContext
-{
-  friend struct PosLookupSubTable;
+struct ChainContextPos : ChainContext {};
 
-  private:
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, position_lookup));
-  }
-};
-
-
-struct ExtensionPos : Extension
+struct ExtensionPos : Extension<ExtensionPos>
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline const struct PosLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(PosLookupSubTable);
-    return StructAtOffset<PosLookupSubTable> (this, offset);
-  }
-
-  inline const Coverage &get_coverage (void) const;
-
-  inline bool apply (hb_apply_context_t *c) const;
-
-  inline bool sanitize (hb_sanitize_context_t *c);
+  typedef struct PosLookupSubTable LookupSubTable;
 };
 
 
 
 /*
  * PosLookup
  */
 
@@ -1421,51 +1361,36 @@ struct PosLookupSubTable
     MarkBase		= 4,
     MarkLig		= 5,
     MarkMark		= 6,
     Context		= 7,
     ChainContext	= 8,
     Extension		= 9
   };
 
-  inline const Coverage &get_coverage (unsigned int lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
+    TRACE_PROCESS (this);
     switch (lookup_type) {
-    case Single:		return u.single.get_coverage ();
-    case Pair:			return u.pair.get_coverage ();
-    case Cursive:		return u.cursive.get_coverage ();
-    case MarkBase:		return u.markBase.get_coverage ();
-    case MarkLig:		return u.markLig.get_coverage ();
-    case MarkMark:		return u.markMark.get_coverage ();
-    case Context:		return u.context.get_coverage ();
-    case ChainContext:		return u.chainContext.get_coverage ();
-    case Extension:		return u.extension.get_coverage ();
-    default:			return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
-  {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.apply (c));
-    case Pair:			return TRACE_RETURN (u.pair.apply (c));
-    case Cursive:		return TRACE_RETURN (u.cursive.apply (c));
-    case MarkBase:		return TRACE_RETURN (u.markBase.apply (c));
-    case MarkLig:		return TRACE_RETURN (u.markLig.apply (c));
-    case MarkMark:		return TRACE_RETURN (u.markMark.apply (c));
-    case Context:		return TRACE_RETURN (u.context.apply (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:		return TRACE_RETURN (u.extension.apply (c));
-    default:			return TRACE_RETURN (false);
+    case Single:		return TRACE_RETURN (u.single.process (c));
+    case Pair:			return TRACE_RETURN (u.pair.process (c));
+    case Cursive:		return TRACE_RETURN (u.cursive.process (c));
+    case MarkBase:		return TRACE_RETURN (u.markBase.process (c));
+    case MarkLig:		return TRACE_RETURN (u.markLig.process (c));
+    case MarkMark:		return TRACE_RETURN (u.markMark.process (c));
+    case Context:		return TRACE_RETURN (u.context.process (c));
+    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
+    case Extension:		return TRACE_RETURN (u.extension.process (c));
+    default:			return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.header.sub_format.sanitize (c))
       return TRACE_RETURN (false);
     switch (lookup_type) {
     case Single:		return TRACE_RETURN (u.single.sanitize (c));
     case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
     case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
     case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
     case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
@@ -1475,17 +1400,17 @@ struct PosLookupSubTable
     case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
     default:			return TRACE_RETURN (true);
     }
   }
 
   protected:
   union {
   struct {
-    USHORT			sub_format;
+    USHORT		sub_format;
   } header;
   SinglePos		single;
   PairPos		pair;
   CursivePos		cursive;
   MarkBasePos		markBase;
   MarkLigPos		markLig;
   MarkMarkPos		markMark;
   ContextPos		context;
@@ -1497,52 +1422,72 @@ struct PosLookupSubTable
 };
 
 
 struct PosLookup : Lookup
 {
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
+  {
+    TRACE_PROCESS (this);
+    unsigned int lookup_type = get_type ();
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return TRACE_RETURN (r);
+    }
+    return TRACE_RETURN (c->default_return_value ());
+  }
+  template <typename context_t>
+  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (NULL);
+    return TRACE_RETURN (process (c));
+  }
+
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
+    hb_get_coverage_context_t c;
     const Coverage *last = NULL;
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
-      if (c != last) {
-        c->add_coverage (glyphs);
-        last = c;
+      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
+      if (coverage != last) {
+        coverage->add_coverage (glyphs);
+        last = coverage;
       }
     }
   }
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-
+    TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
+      return TRACE_RETURN (false);
+    return TRACE_RETURN (process (c));
+  }
 
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).apply (c, lookup_type))
-	return true;
-
-    return false;
-  }
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
 
   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     bool ret = false;
 
     if (unlikely (!c->buffer->len || !c->lookup_mask))
       return false;
 
+    c->set_recurse_func (apply_recurse_func);
     c->set_lookup (*this);
 
     c->buffer->idx = 0;
 
     while (c->buffer->idx < c->buffer->len)
     {
       if ((c->buffer->cur().mask & c->lookup_mask) &&
 	  digest->may_have (c->buffer->cur().codepoint) &&
@@ -1551,17 +1496,17 @@ struct PosLookup : Lookup
       else
 	c->buffer->idx++;
     }
 
     return ret;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
     OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
     return TRACE_RETURN (list.sanitize (c, this, get_type ()));
   }
 };
 
 typedef OffsetListOf<PosLookup> PosLookupList;
 
@@ -1571,25 +1516,21 @@ typedef OffsetListOf<PosLookup> PosLooku
 
 struct GPOS : GSUBGPOS
 {
   static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
 
   inline const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
-  template <typename set_t>
-  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
-  { get_lookup (lookup_index).add_coverage (glyphs); }
-
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
   }
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
@@ -1668,51 +1609,38 @@ GPOS::position_finish (hb_font_t *font H
   HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
   HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
   HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
-inline const Coverage & ExtensionPos::get_coverage (void) const
-{
-  return get_subtable ().get_coverage (get_type ());
-}
-
-inline bool ExtensionPos::apply (hb_apply_context_t *c) const
-{
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE ();
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+template <typename context_t>
+inline typename context_t::return_t PosLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
+  return l.process (c);
+}
 
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+{
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+  const PosLookup &l = gpos.get_lookup (lookup_index);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_property = c->property;
+  c->set_lookup (l);
+  bool ret = l.apply_once (c);
+  c->lookup_props = saved_lookup_props;
+  c->property = saved_property;
+  return ret;
 }
 
 
 #undef attach_lookback
 #undef cursive_chain
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -32,129 +32,154 @@
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 
 namespace OT {
 
 
 struct SingleSubstFormat1
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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);
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      hb_codepoint_t glyph_id = iter.get_glyph ();
+      c->input->add (glyph_id);
+      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
+    }
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* According to the Adobe Annotated OpenType Suite, result is always
      * limited to 16bit. */
     glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
     c->replace_glyph (glyph_id);
 
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs,
 			 int delta)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   SHORT		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct SingleSubstFormat2
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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 ()]);
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      c->output->add (substitute[iter.get_coverage ()]);
+    }
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
 
     glyph_id = substitute[index];
     c->replace_glyph (glyph_id);
 
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<GlyphID> &substitutes,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -162,56 +187,33 @@ struct SingleSubstFormat2
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, substitute);
 };
 
 struct SingleSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    case 2: u.format2.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    case 2: return u.format2.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<GlyphID> &substitutes,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 2;
     int delta;
     if (num_glyphs) {
       format = 1;
       /* TODO(serialize) check for wrap-around */
       delta = substitutes[0] - glyphs[0];
       for (unsigned int i = 1; i < num_glyphs; i++)
@@ -224,17 +226,17 @@ struct SingleSubst
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
     case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
     default:return TRACE_RETURN (false);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
@@ -244,118 +246,132 @@ struct SingleSubst
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
 };
 
 
 struct Sequence
 {
-  friend struct MultipleSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->glyphs->add (substitute[i]);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
 
-    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
+    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++) {
       set_lig_props_for_component (c->buffer->cur(), i);
       c->output_glyph (substitute.array[i], klass);
     }
     c->buffer->skip_glyph ();
 
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (substitute.sanitize (c));
   }
 
   protected:
   ArrayOf<GlyphID>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
 };
 
 struct MultipleSubstFormat1
 {
-  friend struct MultipleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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);
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = sequence.len;
+    for (unsigned int i = 0; i < count; i++)
+	(this+sequence[i]).collect_glyphs (c);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+sequence[index]).apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &substitute_len_list,
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       if (unlikely (!sequence[i].serialize (c, this).serialize (c,
 								substitute_glyphs_list,
 								substitute_len_list[i]))) return TRACE_RETURN (false);
     substitute_len_list.advance (num_glyphs);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -363,65 +379,44 @@ struct MultipleSubstFormat1
 		sequence;		/* Array of Sequence tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, sequence);
 };
 
 struct MultipleSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &substitute_len_list,
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
     default:return TRACE_RETURN (false);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -432,45 +427,60 @@ struct MultipleSubst
 };
 
 
 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
 
 struct AlternateSubstFormat1
 {
-  friend struct AlternateSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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;
 	for (unsigned int i = 0; i < count; i++)
 	  c->glyphs->add (alt_set[i]);
       }
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
+      unsigned int count = alt_set.len;
+      for (unsigned int i = 0; i < count; i++)
+	c->output->add (alt_set[i]);
+    }
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const AlternateSet &alt_set = this+alternateSet[index];
 
     if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
 
     hb_mask_t glyph_mask = c->buffer->cur().mask;
     hb_mask_t lookup_mask = c->lookup_mask;
@@ -489,30 +499,30 @@ struct AlternateSubstFormat1
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &alternate_len_list,
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_glyphs; i++)
       if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
 								    alternate_glyphs_list,
 								    alternate_len_list[i]))) return TRACE_RETURN (false);
     alternate_len_list.advance (num_glyphs);
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -520,65 +530,44 @@ struct AlternateSubstFormat1
 		alternateSet;		/* Array of AlternateSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, alternateSet);
 };
 
 struct AlternateSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 Supplier<unsigned int> &alternate_len_list,
 			 unsigned int num_glyphs,
 			 Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
     default:return TRACE_RETURN (false);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -586,51 +575,57 @@ struct AlternateSubst
   USHORT		format;		/* Format identifier */
   AlternateSubstFormat1	format1;
   } u;
 };
 
 
 struct Ligature
 {
-  friend struct LigatureSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = component.len;
     for (unsigned int i = 1; i < count; i++)
       if (!c->glyphs->has (component[i]))
         return;
     c->glyphs->add (ligGlyph);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      c->input->add (component[i]);
+    c->output->add (ligGlyph);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
+    TRACE_WOULD_APPLY (this);
     if (c->len != component.len)
-      return false;
+      return TRACE_RETURN (false);
 
     for (unsigned int i = 1; i < c->len; i++)
       if (likely (c->glyphs[i] != component[i]))
-	return false;
+	return TRACE_RETURN (false);
 
-    return true;
+    return TRACE_RETURN (true);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int count = component.len;
     if (unlikely (count < 1)) return TRACE_RETURN (false);
 
-    unsigned int end_offset;
-    bool is_mark_ligature;
-    unsigned int total_component_count;
+    unsigned int end_offset = 0;
+    bool is_mark_ligature = false;
+    unsigned int total_component_count = 0;
 
     if (likely (!match_input (c, count,
 			      &component[1],
 			      match_glyph,
 			      NULL,
 			      &end_offset,
 			      &is_mark_ligature,
 			      &total_component_count)))
@@ -651,173 +646,188 @@ struct Ligature
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 GlyphID ligature,
 			 Supplier<GlyphID> &components, /* Starting from second */
 			 unsigned int num_components /* Including first component */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     ligGlyph = ligature;
     if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
   }
 
   protected:
   GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
   HeadlessArrayOf<GlyphID>
 		component;		/* Array of component GlyphIDs--start
 					 * with the second  component--ordered
 					 * in writing direction */
   public:
   DEFINE_SIZE_ARRAY (4, component);
 };
 
 struct LigatureSet
 {
-  friend struct LigatureSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
       (this+ligature[i]).closure (c);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      (this+ligature[i]).collect_glyphs (c);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
+    TRACE_WOULD_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const Ligature &lig = this+ligature[i];
       if (lig.would_apply (c))
-        return true;
+        return TRACE_RETURN (true);
     }
-    return false;
+    return TRACE_RETURN (false);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
       const Ligature &lig = this+ligature[i];
       if (lig.apply (c)) return TRACE_RETURN (true);
     }
 
     return TRACE_RETURN (false);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &ligatures,
 			 Supplier<unsigned int> &component_count_list,
 			 unsigned int num_ligatures,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_ligatures; i++)
       if (unlikely (!ligature[i].serialize (c, this).serialize (c,
 								ligatures[i],
 								component_list,
 								component_count_list[i]))) return TRACE_RETURN (false);
     ligatures.advance (num_ligatures);
     component_count_list.advance (num_ligatures);
     return TRACE_RETURN (true);
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligature.sanitize (c, this));
   }
 
   protected:
   OffsetArrayOf<Ligature>
 		ligature;		/* Array LigatureSet tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, ligature);
 };
 
 struct LigatureSubstFormat1
 {
-  friend struct LigatureSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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);
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
+    }
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
+    TRACE_WOULD_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return TRACE_RETURN (lig_set.would_apply (c));
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
     return TRACE_RETURN (lig_set.apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &first_glyphs,
 			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
 			 unsigned int num_first_glyphs,
 			 Supplier<GlyphID> &ligatures_list,
 			 Supplier<unsigned int> &component_count_list,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
     if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < num_first_glyphs; i++)
       if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
 								   ligatures_list,
 								   component_count_list,
 								   ligature_per_first_glyph_count_list[i],
 								   component_list))) return TRACE_RETURN (false);
     ligature_per_first_glyph_count_list.advance (num_first_glyphs);
     if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
@@ -825,169 +835,79 @@ struct LigatureSubstFormat1
 		ligatureSet;		/* Array LigatureSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ligatureSet);
 };
 
 struct LigatureSubst
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &first_glyphs,
 			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
 			 unsigned int num_first_glyphs,
 			 Supplier<GlyphID> &ligatures_list,
 			 Supplier<unsigned int> &component_count_list,
 			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
     unsigned int format = 1;
     u.format.set (format);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
 						      ligatures_list, component_count_list, component_list));
     default:return TRACE_RETURN (false);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
   union {
   USHORT		format;		/* Format identifier */
   LigatureSubstFormat1	format1;
   } u;
 };
 
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
-
-struct ContextSubst : Context
-{
-  friend struct SubstLookupSubTable;
-
-  private:
+struct ContextSubst : Context {};
 
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    return Context::closure (c, closure_lookup);
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, substitute_lookup));
-  }
-};
-
-struct ChainContextSubst : ChainContext
-{
-  friend struct SubstLookupSubTable;
-
-  private:
+struct ChainContextSubst : ChainContext {};
 
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    return ChainContext::closure (c, closure_lookup);
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
-  }
-};
-
-
-struct ExtensionSubst : Extension
+struct ExtensionSubst : Extension<ExtensionSubst>
 {
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-  inline const struct SubstLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(SubstLookupSubTable);
-    return StructAtOffset<SubstLookupSubTable> (this, offset);
-  }
-
-  inline void closure (hb_closure_context_t *c) const;
-
-  inline const Coverage &get_coverage (void) const;
-
-  inline bool would_apply (hb_would_apply_context_t *c) const;
-
-  inline bool apply (hb_apply_context_t *c) const;
-
-  inline bool sanitize (hb_sanitize_context_t *c);
+  typedef struct SubstLookupSubTable LookupSubTable;
 
   inline bool is_reverse (void) const;
 };
 
 
 struct ReverseChainSingleSubstFormat1
 {
-  friend struct ReverseChainSingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
 
     count = backtrack.len;
     for (unsigned int i = 0; i < count; i++)
       if (!(this+backtrack[i]).intersects (c->glyphs))
         return;
@@ -1000,28 +920,58 @@ struct ReverseChainSingleSubstFormat1
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     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 ()]);
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    (this+coverage).add_coverage (c->input);
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+backtrack[i]).add_coverage (c->before);
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+lookahead[i]).add_coverage (c->after);
+
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
   inline const Coverage &get_coverage (void) const
   {
     return this+coverage;
   }
 
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
       return TRACE_RETURN (false); /* No chaining to this type */
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
     if (match_backtrack (c,
 			 backtrack.len, (USHORT *) backtrack.array,
 			 match_coverage, this) &&
@@ -1034,17 +984,17 @@ struct ReverseChainSingleSubstFormat1
       c->buffer->idx--; /* Reverse! */
       return TRACE_RETURN (true);
     }
 
     return TRACE_RETURN (false);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return TRACE_RETURN (false);
     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!lookahead.sanitize (c, this))
       return TRACE_RETURN (false);
     ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     return TRACE_RETURN (substitute.sanitize (c));
   }
@@ -1066,48 +1016,28 @@ struct ReverseChainSingleSubstFormat1
 		substituteX;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
   DEFINE_SIZE_MIN (10);
 };
 
 struct ReverseChainSingleSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
   protected:
@@ -1133,92 +1063,35 @@ struct SubstLookupSubTable
     Alternate		= 3,
     Ligature		= 4,
     Context		= 5,
     ChainContext	= 6,
     Extension		= 7,
     ReverseChainSingle	= 8
   };
 
-  inline void closure (hb_closure_context_t *c,
-		       unsigned int    lookup_type) const
-  {
-    TRACE_CLOSURE ();
-    switch (lookup_type) {
-    case Single:		u.single.closure (c); break;
-    case Multiple:		u.multiple.closure (c); break;
-    case Alternate:		u.alternate.closure (c); break;
-    case Ligature:		u.ligature.closure (c); break;
-    case Context:		u.context.closure (c); break;
-    case ChainContext:		u.chainContext.closure (c); break;
-    case Extension:		u.extension.closure (c); break;
-    case ReverseChainSingle:	u.reverseChainContextSingle.closure (c); break;
-    default:                    break;
-    }
-  }
-
-  inline const Coverage &get_coverage (unsigned int lookup_type) const
-  {
-    switch (lookup_type) {
-    case Single:		return u.single.get_coverage ();
-    case Multiple:		return u.multiple.get_coverage ();
-    case Alternate:		return u.alternate.get_coverage ();
-    case Ligature:		return u.ligature.get_coverage ();
-    case Context:		return u.context.get_coverage ();
-    case ChainContext:		return u.chainContext.get_coverage ();
-    case Extension:		return u.extension.get_coverage ();
-    case ReverseChainSingle:	return u.reverseChainContextSingle.get_coverage ();
-    default:			return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c,
-			   unsigned int lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
   {
-    TRACE_WOULD_APPLY ();
-    if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
-    if (c->len == 1) {
-      switch (lookup_type) {
-      case Single:
-      case Multiple:
-      case Alternate:
-      case ReverseChainSingle:
-        return true;
-      }
-    }
-
-    /* Only need to look further for lookups that support substitutions
-     * of input longer than 1. */
+    TRACE_PROCESS (this);
     switch (lookup_type) {
-    case Ligature:		return u.ligature.would_apply (c);
-    case Context:		return u.context.would_apply (c);
-    case ChainContext:		return u.chainContext.would_apply (c);
-    case Extension:		return u.extension.would_apply (c);
-    default:			return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
-  {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:		return TRACE_RETURN (u.single.apply (c));
-    case Multiple:		return TRACE_RETURN (u.multiple.apply (c));
-    case Alternate:		return TRACE_RETURN (u.alternate.apply (c));
-    case Ligature:		return TRACE_RETURN (u.ligature.apply (c));
-    case Context:		return TRACE_RETURN (u.context.apply (c));
-    case ChainContext:		return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:		return TRACE_RETURN (u.extension.apply (c));
-    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
-    default:			return TRACE_RETURN (false);
+    case Single:		return TRACE_RETURN (u.single.process (c));
+    case Multiple:		return TRACE_RETURN (u.multiple.process (c));
+    case Alternate:		return TRACE_RETURN (u.alternate.process (c));
+    case Ligature:		return TRACE_RETURN (u.ligature.process (c));
+    case Context:		return TRACE_RETURN (u.context.process (c));
+    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
+    case Extension:		return TRACE_RETURN (u.extension.process (c));
+    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.process (c));
+    default:			return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.header.sub_format.sanitize (c))
       return TRACE_RETURN (false);
     switch (lookup_type) {
     case Single:		return TRACE_RETURN (u.single.sanitize (c));
     case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
     case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
     case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
     case Context:		return TRACE_RETURN (u.context.sanitize (c));
@@ -1259,72 +1132,86 @@ 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 void closure (hb_closure_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
+    TRACE_PROCESS (this);
     unsigned int lookup_type = get_type ();
     unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      get_subtable (i).closure (c, lookup_type);
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return TRACE_RETURN (r);
+    }
+    return TRACE_RETURN (c->default_return_value ());
+  }
+  template <typename context_t>
+  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
+
+  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    c->set_recurse_func (process_recurse_func<hb_closure_context_t>);
+    return TRACE_RETURN (process (c));
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (process_recurse_func<hb_collect_glyphs_context_t>);
+    return TRACE_RETURN (process (c));
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
   {
+    hb_get_coverage_context_t c;
     const Coverage *last = NULL;
     unsigned int count = get_subtable_count ();
     for (unsigned int i = 0; i < count; i++) {
-      const Coverage *c = &get_subtable (i).get_coverage (get_type ());
-      if (c != last) {
-        c->add_coverage (glyphs);
-        last = c;
+      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
+      if (coverage != last) {
+        coverage->add_coverage (glyphs);
+        last = coverage;
       }
     }
   }
 
   inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
   {
-    if (unlikely (!c->len)) return false;
-    if (!digest->may_have (c->glyphs[0])) return false;
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).would_apply (c, lookup_type))
-	return true;
-    return false;
+    TRACE_WOULD_APPLY (this);
+    if (unlikely (!c->len))  return TRACE_RETURN (false);
+    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
+      return TRACE_RETURN (process (c));
   }
 
   inline bool apply_once (hb_apply_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-
+    TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
-
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).apply (c, lookup_type))
-	return true;
-
-    return false;
+      return TRACE_RETURN (false);
+    return TRACE_RETURN (process (c));
   }
 
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
   inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
   {
     bool ret = false;
 
     if (unlikely (!c->buffer->len || !c->lookup_mask))
       return false;
 
+    c->set_recurse_func (apply_recurse_func);
     c->set_lookup (*this);
 
     if (likely (!is_reverse ()))
     {
 	/* in/out forward substitution */
 	c->buffer->clear_output ();
 	c->buffer->idx = 0;
 
@@ -1356,77 +1243,75 @@ struct SubstLookup : Lookup
 
 	}
 	while ((int) c->buffer->idx >= 0);
     }
 
     return ret;
   }
 
-  private:
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
 						  unsigned int i)
   { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
-  public:
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
 			        Supplier<GlyphID> &glyphs,
 			        Supplier<GlyphID> &substitutes,
 			        unsigned int num_glyphs)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
   }
 
   inline bool serialize_multiple (hb_serialize_context_t *c,
 				  uint32_t lookup_props,
 				  Supplier<GlyphID> &glyphs,
 				  Supplier<unsigned int> &substitute_len_list,
 				  unsigned int num_glyphs,
 				  Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
 									 substitute_glyphs_list));
   }
 
   inline bool serialize_alternate (hb_serialize_context_t *c,
 				   uint32_t lookup_props,
 				   Supplier<GlyphID> &glyphs,
 				   Supplier<unsigned int> &alternate_len_list,
 				   unsigned int num_glyphs,
 				   Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
 									  alternate_glyphs_list));
   }
 
   inline bool serialize_ligature (hb_serialize_context_t *c,
 				  uint32_t lookup_props,
 				  Supplier<GlyphID> &first_glyphs,
 				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
 				  unsigned int num_first_glyphs,
 				  Supplier<GlyphID> &ligatures_list,
 				  Supplier<unsigned int> &component_count_list,
 				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
-    TRACE_SERIALIZE ();
+    TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
     return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
 									 ligatures_list, component_count_list, component_list));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c)
   {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
     OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
     if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
 
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
        * have the same type.  This is specially important if one has
@@ -1451,29 +1336,21 @@ typedef OffsetListOf<SubstLookup> SubstL
 
 struct GSUB : GSUBGPOS
 {
   static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
 
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
-  template <typename set_t>
-  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
-  { get_lookup (lookup_index).add_coverage (glyphs); }
-
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  inline void closure_lookup (hb_closure_context_t *c,
-			      unsigned int          lookup_index) const
-  { return get_lookup (lookup_index).closure (c); }
-
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
     OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
   }
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
@@ -1496,78 +1373,42 @@ GSUB::substitute_start (hb_font_t *font,
 void
 GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
 {
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
-inline void ExtensionSubst::closure (hb_closure_context_t *c) const
-{
-  get_subtable ().closure (c, get_type ());
-}
-
-inline const Coverage & ExtensionSubst::get_coverage (void) const
-{
-  return get_subtable ().get_coverage (get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
-{
-  return get_subtable ().would_apply (c, get_type ());
-}
-
-inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
-{
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE ();
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
 inline bool ExtensionSubst::is_reverse (void) const
 {
   unsigned int type = get_type ();
   if (unlikely (type == SubstLookupSubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
+    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
+template <typename context_t>
+inline typename context_t::return_t SubstLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return;
-
-  c->nesting_level_left--;
-  l.closure (c);
-  c->nesting_level_left++;
+  return l.process (c);
 }
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
-
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+  unsigned int saved_lookup_props = c->lookup_props;
+  unsigned int saved_property = c->property;
+  c->set_lookup (l);
+  bool ret = l.apply_once (c);
+  c->lookup_props = saved_lookup_props;
+  c->property = saved_property;
+  return ret;
 }
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -32,113 +32,264 @@
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-set-private.hh"
 
 
 namespace OT {
 
 
+
+#define TRACE_PROCESS(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_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
-#define TRACE_CLOSURE() \
-	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
-
+#define TRACE_CLOSURE(this) \
+	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
 
 struct hb_closure_context_t
 {
+  inline const char *get_name (void) { return "CLOSURE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
+  typedef hb_void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t process (const T &obj) { obj.closure (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return HB_VOID;
+  }
+
   hb_face_t *face;
   hb_set_t *glyphs;
+  recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
-
   hb_closure_context_t (hb_face_t *face_,
 			hb_set_t *glyphs_,
 		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
 			  face (face_),
 			  glyphs (glyphs_),
+			  recurse_func (NULL),
 			  nesting_level_left (nesting_level_left_),
 			  debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
-/* TODO Add TRACE_RETURN annotation to gsub. */
 #ifndef HB_DEBUG_WOULD_APPLY
 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 #endif
 
-#define TRACE_WOULD_APPLY() \
-	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "%d glyphs", c->len);
-
+#define TRACE_WOULD_APPLY(this) \
+	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "%d glyphs", c->len);
 
 struct hb_would_apply_context_t
 {
+  inline const char *get_name (void) { return "WOULD_APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
+  typedef bool return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.would_apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const return_t r) const { return r; }
+
   hb_face_t *face;
   const hb_codepoint_t *glyphs;
   unsigned int len;
   bool zero_context;
   unsigned int debug_depth;
 
   hb_would_apply_context_t (hb_face_t *face_,
 			    const hb_codepoint_t *glyphs_,
 			    unsigned int len_,
 			    bool zero_context_) :
 			      face (face_),
 			      glyphs (glyphs_),
 			      len (len_),
 			      zero_context (zero_context_),
-			      debug_depth (0) {};
+			      debug_depth (0) {}
 };
 
 
+
+#ifndef HB_DEBUG_COLLECT_GLYPHS
+#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
+#endif
+
+#define TRACE_COLLECT_GLYPHS(this) \
+	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
+
+struct hb_collect_glyphs_context_t
+{
+  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
+  typedef hb_void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t process (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+     * past the previous check.  For GSUB, we only want to collect the output
+     * glyphs in the recursion.  If output is not requested, we can go home now. */
+
+    if (output == hb_set_get_empty ())
+      return HB_VOID;
+
+    hb_set_t *old_before = before;
+    hb_set_t *old_input  = input;
+    hb_set_t *old_after  = after;
+    before = input = after = hb_set_get_empty ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+
+    before = old_before;
+    input  = old_input;
+    after  = old_after;
+
+    return HB_VOID;
+  }
+
+  hb_face_t *face;
+  hb_set_t *before;
+  hb_set_t *input;
+  hb_set_t *after;
+  hb_set_t *output;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int debug_depth;
+
+  hb_collect_glyphs_context_t (hb_face_t *face_,
+			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
+			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
+			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
+			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
+			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+			      face (face_),
+			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
+			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
+			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
+			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
+			      recurse_func (NULL),
+			      nesting_level_left (nesting_level_left_),
+			      debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
+struct hb_get_coverage_context_t
+{
+  inline const char *get_name (void) { return "GET_COVERAGE"; }
+  static const unsigned int max_debug_depth = 0;
+  typedef const Coverage &return_t;
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.get_coverage (); }
+  static return_t default_return_value (void) { return Null(Coverage); }
+
+  hb_get_coverage_context_t (void) :
+			    debug_depth (0) {}
+
+  unsigned int debug_depth;
+};
+
+
+
 #ifndef HB_DEBUG_APPLY
 #define HB_DEBUG_APPLY (HB_DEBUG+0)
 #endif
 
-#define TRACE_APPLY() \
-	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
-
+#define TRACE_APPLY(this) \
+	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
 
 struct hb_apply_context_t
 {
+  inline const char *get_name (void) { return "APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+  typedef bool return_t;
+  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t process (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (const 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_font_t *font;
   hb_face_t *face;
   hb_buffer_t *buffer;
   hb_direction_t direction;
   hb_mask_t lookup_mask;
+  recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int lookup_props;
   unsigned int property; /* propety of first glyph */
-  unsigned int debug_depth;
   const GDEF &gdef;
   bool has_glyph_classes;
+  unsigned int debug_depth;
 
 
   hb_apply_context_t (hb_font_t *font_,
 		      hb_buffer_t *buffer_,
 		      hb_mask_t lookup_mask_) :
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
+			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
-			lookup_props (0), property (0), debug_depth (0),
+			lookup_props (0), property (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
-			has_glyph_classes (gdef.has_glyph_classes ()) {}
+			has_glyph_classes (gdef.has_glyph_classes ()),
+			debug_depth (0) {}
 
-  void set_lookup_props (unsigned int lookup_props_) {
-    lookup_props = lookup_props_;
-  }
-
-  void set_lookup (const Lookup &l) {
-    lookup_props = l.get_props ();
-  }
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+  void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+  void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
 
   struct mark_skipping_forward_iterator_t
   {
     inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
 					     unsigned int start_index_,
 					     unsigned int num_items_,
 					     bool context_match = false)
     {
@@ -259,17 +410,17 @@ struct hb_apply_context_t
 		    unsigned int    lookup_props) const
   {
     /* Not covered, if, for example, glyph class is ligature and
      * lookup_props includes LookupFlags::IgnoreLigatures
      */
     if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
       return false;
 
-    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
+    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
       return match_properties_mark (glyph, glyph_props, lookup_props);
 
     return true;
   }
 
   inline bool
   check_glyph_property (hb_glyph_info_t *info,
 			unsigned int  lookup_props,
@@ -290,17 +441,17 @@ struct hb_apply_context_t
   {
     unsigned int property;
 
     property = info->glyph_props();
     if (property_out)
       *property_out = property;
 
     /* If it's a mark, skip it if we don't accept it. */
-    if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
+    if (unlikely (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
       return !match_properties (info->codepoint, property, lookup_props);
 
     /* If not a mark, don't skip. */
     return false;
   }
 
 
   inline bool should_mark_skip_current_glyph (void) const
@@ -334,31 +485,33 @@ struct hb_apply_context_t
     set_class (glyph_index, class_guess);
     buffer->cur().codepoint = 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);
-typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
-typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
-  closure_lookup_func_t closure;
+};
+struct ContextCollectGlyphsFuncs
+{
+  collect_glyphs_func_t collect;
 };
 struct ContextApplyFuncs
 {
   match_func_t match;
-  apply_lookup_func_t apply;
 };
 
+
 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
@@ -377,32 +530,57 @@ static inline bool intersects_array (hb_
 {
   for (unsigned int i = 0; i < count; i++)
     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
       return false;
   return true;
 }
 
 
+static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+  glyphs->add (value);
+}
+static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  class_def.add_class (glyphs, value);
+}
+static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  (data+coverage).add_coverage (glyphs);
+}
+static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
+				  hb_set_t *glyphs,
+				  unsigned int count,
+				  const USHORT values[],
+				  collect_glyphs_func_t collect_func,
+				  const void *collect_data)
+{
+  for (unsigned int i = 0; i < count; i++)
+    collect_func (glyphs, values[i], collect_data);
+}
+
+
 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
-
 static inline bool would_match_input (hb_would_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)
 {
   if (count != c->len)
     return false;
@@ -417,17 +595,17 @@ static inline bool match_input (hb_apply
 				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,
 				bool *p_is_mark_ligature = NULL,
 				unsigned int *p_total_component_count = NULL)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
   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.
@@ -440,17 +618,17 @@ 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->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+  bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
 
   unsigned int total_component_count = 0;
   total_component_count += get_lig_num_comps (c->buffer->cur());
 
   unsigned int first_lig_id = get_lig_id (c->buffer->cur());
   unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
 
   for (unsigned int i = 1; i < count; i++)
@@ -473,37 +651,37 @@ static inline bool match_input (hb_apply
     } 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 && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+    is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
     total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
   }
 
   if (end_offset)
     *end_offset = skippy_iter.idx - c->buffer->idx + 1;
 
   if (p_is_mark_ligature)
     *p_is_mark_ligature = is_mark_ligature;
 
   if (p_total_component_count)
     *p_total_component_count = total_component_count;
 
   return 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 */
+				 const USHORT input[] HB_UNUSED, /* Array of input values--start with second glyph */
 				 hb_codepoint_t lig_glyph,
-				 match_func_t match_func,
-				 const void *match_data,
+				 match_func_t match_func HB_UNUSED,
+				 const void *match_data HB_UNUSED,
 				 bool is_mark_ligature,
 				 unsigned int total_component_count)
 {
   /*
    * - 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
@@ -525,17 +703,17 @@ static inline void ligate_input (hb_appl
    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
    *   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_CLASS_LIGATURE;
+  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 components_so_far = last_num_components;
 
   if (!is_mark_ligature)
     set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
   c->replace_glyph (lig_glyph, klass);
@@ -574,17 +752,17 @@ static inline void ligate_input (hb_appl
 }
 
 static inline bool match_backtrack (hb_apply_context_t *c,
 				    unsigned int count,
 				    const USHORT backtrack[],
 				    match_func_t match_func,
 				    const void *match_data)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
   if (skippy_iter.has_no_chance ())
     return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
   {
     if (!skippy_iter.prev ())
@@ -599,17 +777,17 @@ static inline bool match_backtrack (hb_a
 
 static inline bool match_lookahead (hb_apply_context_t *c,
 				    unsigned int count,
 				    const USHORT lookahead[],
 				    match_func_t match_func,
 				    const void *match_data,
 				    unsigned int offset)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
 
   hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
   if (skippy_iter.has_no_chance ())
     return TRACE_RETURN (false);
 
   for (unsigned int i = 0; i < count; i++)
   {
     if (!skippy_iter.next ())
@@ -622,45 +800,45 @@ static inline bool match_lookahead (hb_a
   return TRACE_RETURN (true);
 }
 
 
 
 struct LookupRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   USHORT	sequenceIndex;		/* Index into current glyph
 					 * sequence--first glyph = 0 */
   USHORT	lookupListIndex;	/* Lookup to apply to that
 					 * position--zero--based */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
-static inline void closure_lookup (hb_closure_context_t *c,
-				   unsigned int lookupCount,
-				   const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-				   closure_lookup_func_t closure_func)
+template <typename context_t>
+static inline void recurse_lookups (context_t *c,
+				    unsigned int lookupCount,
+				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
-    closure_func (c, lookupRecord->lookupListIndex);
+    c->recurse (lookupRecord->lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 unsigned int lookupCount,
-				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-				 apply_lookup_func_t apply_func)
+				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
-  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+  TRACE_APPLY (NULL);
+
   unsigned int end = c->buffer->len;
   if (unlikely (count == 0 || c->buffer->idx + count > end))
     return TRACE_RETURN (false);
 
   /* TODO We don't support lookupRecord arrays that are not increasing:
    *      Should be easy for in_place ones at least. */
 
   /* Note: If sublookup is reverse, it will underflow after the first loop
@@ -679,17 +857,17 @@ static inline bool apply_lookup (hb_appl
 	return TRACE_RETURN (true);
     }
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
     {
       unsigned int old_pos = c->buffer->idx;
 
       /* Apply a lookup */
-      bool done = apply_func (c, lookupRecord->lookupListIndex);
+      bool done = c->recurse (lookupRecord->lookupListIndex);
 
       lookupRecord++;
       lookupCount--;
       /* Err, this is wrong if the lookup jumped over some glyphs */
       i += c->buffer->idx - old_pos;
       if (unlikely (c->buffer->idx == end))
 	return TRACE_RETURN (true);
 
@@ -713,43 +891,61 @@ static inline bool apply_lookup (hb_appl
 /* Contextual lookups */
 
 struct ContextClosureLookupContext
 {
   ContextClosureFuncs funcs;
   const void *intersects_data;
 };
 
+struct ContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data;
+};
+
 struct ContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data;
 };
 
 static inline void context_closure_lookup (hb_closure_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[],
 					   ContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data))
-    closure_lookup (c,
-		    lookupCount, lookupRecord,
-		    lookup_context.funcs.closure);
+    recurse_lookups (c,
+		     lookupCount, lookupRecord);
 }
 
+static inline void context_collect_glyphs_lookup (hb_collect_glyphs_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[],
+						  ContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->input,
+		 inputCount ? inputCount - 1 : 0, input,
+		 lookup_context.funcs.collect, lookup_context.collect_data);
+  recurse_lookups (c,
+		   lookupCount, lookupRecord);
+}
 
 static inline bool context_would_apply_lookup (hb_would_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[],
+					       unsigned int lookupCount HB_UNUSED,
+					       const LookupRecord lookupRecord[] HB_UNUSED,
 					       ContextApplyLookupContext &lookup_context)
 {
   return would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data);
 }
 static inline bool context_apply_lookup (hb_apply_context_t *c,
 					 unsigned int inputCount, /* Including the first glyph (not matched) */
@@ -758,53 +954,58 @@ static inline bool context_apply_lookup 
 					 const LookupRecord lookupRecord[],
 					 ContextApplyLookupContext &lookup_context)
 {
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data)
       && apply_lookup (c,
 		       inputCount,
-		       lookupCount, lookupRecord,
-		       lookup_context.funcs.apply);
+		       lookupCount, lookupRecord);
 }
 
 struct Rule
 {
-  friend struct RuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    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);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+    context_collect_glyphs_lookup (c,
+				   inputCount, input,
+				   lookupCount, lookupRecord,
+				   lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return inputCount.sanitize (c)
 	&& lookupCount.sanitize (c)
 	&& c->check_range (input,
 			   input[0].static_size * inputCount
 			   + lookupRecordX[0].static_size * lookupCount);
   }
 
   protected:
@@ -819,114 +1020,138 @@ struct Rule
   public:
   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
 };
 
 struct RuleSet
 {
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    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);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).would_apply (c, lookup_context))
         return TRACE_RETURN (true);
     }
     return TRACE_RETURN (false);
   }
 
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
       if ((this+rule[i]).apply (c, lookup_context))
         return TRACE_RETURN (true);
     }
     return TRACE_RETURN (false);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
   protected:
   OffsetArrayOf<Rule>
 		rule;			/* Array of Rule tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 
 struct ContextFormat1
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       NULL
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (cov.intersects_coverage (c->glyphs, i)) {
 	const RuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
-    const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
+    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ContextApplyLookupContext lookup_context = {
-      {match_glyph, NULL},
+      {match_glyph},
       NULL
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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);
     if (likely (index == NOT_COVERED))
       return TRACE_RETURN (false);
 
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       NULL
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -935,73 +1160,90 @@ struct ContextFormat1
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 
 struct ContextFormat2
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &class_def = this+classDef;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
-      NULL
+      {intersects_class},
+      &class_def
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (class_def.intersects_class (c->glyphs, i)) {
 	const RuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
   }
 
-  inline bool would_apply (hb_would_apply_context_t *c) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
 
     const ClassDef &class_def = this+classDef;
-    unsigned int index = class_def (c->glyphs[0]);
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ClassDef &class_def = this+classDef;
+    unsigned int index = class_def.get_class (c->glyphs[0]);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_class, NULL},
+      {match_class},
       &class_def
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const ClassDef &class_def = this+classDef;
-    index = class_def (c->buffer->cur().codepoint);
+    index = class_def.get_class (c->buffer->cur().codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       &class_def
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1013,65 +1255,83 @@ struct ContextFormat2
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (8, ruleSet);
 };
 
 
 struct ContextFormat3
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    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 = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       this
     };
     context_closure_lookup (c,
 			    glyphCount, (const USHORT *) (coverage + 1),
 			    lookupCount, lookupRecord,
 			    lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage[0]).add_coverage (c->input);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      this
+    };
+
+    context_collect_glyphs_lookup (c,
+				   glyphCount, (const USHORT *) (coverage + 1),
+				   lookupCount, lookupRecord,
+				   lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
-      {match_coverage, NULL},
+      {match_coverage},
       this
     };
     return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
+    return this+coverage[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       this
     };
     return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     unsigned int count = glyphCount;
     if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < count; i++)
       if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
     LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
     return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   }
@@ -1087,62 +1347,30 @@ struct ContextFormat3
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
 };
 
 struct Context
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return this + u.format1.coverage;
-    case 2: return this + u.format2.coverage;
-    case 3: return this + u.format3.coverage[0];
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    case 2: return u.format2.would_apply (c);
-    case 3: return u.format3.would_apply (c);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    case 3: return TRACE_RETURN (c->process (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     case 3: return TRACE_RETURN (u.format3.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
@@ -1160,16 +1388,22 @@ struct Context
 /* Chaining Contextual lookups */
 
 struct ChainContextClosureLookupContext
 {
   ContextClosureFuncs funcs;
   const void *intersects_data[3];
 };
 
+struct ChainContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data[3];
+};
+
 struct ChainContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
   const void *match_data[3];
 };
 
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
 						 unsigned int backtrackCount,
@@ -1186,30 +1420,53 @@ static inline void chain_context_closure
 			backtrackCount, backtrack,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
    && intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
   && intersects_array (c,
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
-    closure_lookup (c,
-		    lookupCount, lookupRecord,
-		    lookup_context.funcs.closure);
+    recurse_lookups (c,
+		     lookupCount, lookupRecord);
+}
+
+static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+						        unsigned int backtrackCount,
+						        const USHORT backtrack[],
+						        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[],
+						        ChainContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->before,
+		 backtrackCount, backtrack,
+		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
+  collect_array (c, c->input,
+		 inputCount ? inputCount - 1 : 0, input,
+		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
+  collect_array (c, c->after,
+		 lookaheadCount, lookahead,
+		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
+  recurse_lookups (c,
+		   lookupCount, lookupRecord);
 }
 
 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
 						     unsigned int backtrackCount,
-						     const USHORT backtrack[],
+						     const USHORT backtrack[] HB_UNUSED,
 						     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[],
+						     const USHORT lookahead[] HB_UNUSED,
+						     unsigned int lookupCount HB_UNUSED,
+						     const LookupRecord lookupRecord[] HB_UNUSED,
 						     ChainContextApplyLookupContext &lookup_context)
 {
   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
       && would_match_input (c,
 			    inputCount, input,
 			    lookup_context.funcs.match, lookup_context.match_data[1]);
 }
 
@@ -1219,83 +1476,91 @@ 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;
+  unsigned int lookahead_offset = 0;
   return match_input (c,
 		      inputCount, input,
 		      lookup_context.funcs.match, lookup_context.match_data[1],
 		      &lookahead_offset)
       && 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)
       && apply_lookup (c,
 		       inputCount,
-		       lookupCount, lookupRecord,
-		       lookup_context.funcs.apply);
+		       lookupCount, lookupRecord);
 }
 
 struct ChainRule
 {
-  friend struct ChainRuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    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,
 				  input.len, input.array,
 				  lookahead.len, lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (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_collect_glyphs_lookup (c,
+					 backtrack.len, backtrack.array,
+					 input.len, input.array,
+					 lookahead.len, lookahead.array,
+					 lookup.len, lookup.array,
+					 lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (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);
     return TRACE_RETURN (chain_context_would_apply_lookup (c,
 							   backtrack.len, backtrack.array,
 							   input.len, input.array,
 							   lookahead.len, lookahead.array, lookup.len,
 							   lookup.array, lookup_context));
   }
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (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);
     return TRACE_RETURN (chain_context_apply_lookup (c,
 						     backtrack.len, backtrack.array,
 						     input.len, input.array,
 						     lookahead.len, lookahead.array, lookup.len,
 						     lookup.array, lookup_context));
   }
 
-  public:
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     if (!input.sanitize (c)) return TRACE_RETURN (false);
     ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return TRACE_RETURN (lookup.sanitize (c));
   }
@@ -1317,109 +1582,133 @@ struct ChainRule
   public:
   DEFINE_SIZE_MIN (8);
 };
 
 struct ChainRuleSet
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    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);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).would_apply (c, lookup_context))
         return TRACE_RETURN (true);
 
     return TRACE_RETURN (false);
   }
 
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).apply (c, lookup_context))
         return TRACE_RETURN (true);
 
     return TRACE_RETURN (false);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
   protected:
   OffsetArrayOf<ChainRule>
 		rule;			/* Array of ChainRule tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 struct ChainContextFormat1
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       {NULL, NULL, NULL}
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (cov.intersects_coverage (c->glyphs, i)) {
 	const ChainRuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
-    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
+    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph, NULL},
+      {match_glyph},
       {NULL, NULL, NULL}
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       {NULL, NULL, NULL}
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 1 */
   OffsetTo<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
@@ -1427,83 +1716,109 @@ struct ChainContextFormat1
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 struct ChainContextFormat2
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
+      {intersects_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
     };
 
     unsigned int count = ruleSet.len;
     for (unsigned int i = 0; i < count; i++)
       if (input_class_def.intersects_class (c->glyphs, i)) {
 	const ChainRuleSet &rule_set = this+ruleSet[i];
 	rule_set.closure (c, lookup_context);
       }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (this);
 
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    unsigned int index = input_class_def (c->glyphs[0]);
+    unsigned int index = input_class_def.get_class (c->glyphs[0]);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class, NULL},
-      {NULL, &input_class_def, NULL}
+      {match_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
     };
     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    index = input_class_def (c->buffer->cur().codepoint);
+    index = input_class_def.get_class (c->buffer->cur().codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
 			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
 			 ruleSet.sanitize (c, this));
   }
 
   protected:
   USHORT	format;			/* Format identifier--format = 2 */
   OffsetTo<Coverage>
@@ -1525,89 +1840,106 @@ struct ChainContextFormat2
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (12, ruleSet);
 };
 
 struct ChainContextFormat3
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       {this, this, this}
     };
     chain_context_closure_lookup (c,
 				  backtrack.len, (const USHORT *) backtrack.array,
 				  input.len, (const USHORT *) input.array + 1,
 				  lookahead.len, (const USHORT *) lookahead.array,
 				  lookup.len, lookup.array,
 				  lookup_context);
   }
 
-  inline const Coverage &get_coverage (void) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
+    TRACE_COLLECT_GLYPHS (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
-    return this+input[0];
+
+    (this+input[0]).add_coverage (c->input);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      {this, this, this}
+    };
+    chain_context_collect_glyphs_lookup (c,
+					 backtrack.len, (const USHORT *) backtrack.array,
+					 input.len, (const USHORT *) input.array + 1,
+					 lookahead.len, (const USHORT *) lookahead.array,
+					 lookup.len, lookup.array,
+					 lookup_context);
   }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_WOULD_APPLY ();
+    TRACE_WOULD_APPLY (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);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage, NULL},
+      {match_coverage},
       {this, this, this}
     };
     return TRACE_RETURN (chain_context_would_apply_lookup (c,
 							   backtrack.len, (const USHORT *) backtrack.array,
 							   input.len, (const USHORT *) input.array + 1,
 							   lookahead.len, (const USHORT *) lookahead.array,
 							   lookup.len, lookup.array, lookup_context));
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    return this+input[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
-    unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
+    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       {this, this, this}
     };
     return TRACE_RETURN (chain_context_apply_lookup (c,
 						     backtrack.len, (const USHORT *) backtrack.array,
 						     input.len, (const USHORT *) input.array + 1,
 						     lookahead.len, (const USHORT *) lookahead.array,
 						     lookup.len, lookup.array, lookup_context));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return TRACE_RETURN (lookup.sanitize (c));
   }
@@ -1630,62 +1962,30 @@ struct ChainContextFormat3
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
   DEFINE_SIZE_MIN (10);
 };
 
 struct ChainContext
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
   {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline const Coverage &get_coverage (void) const
-  {
+    TRACE_PROCESS (this);
     switch (u.format) {
-    case 1: return this + u.format1.coverage;
-    case 2: return this + u.format2.coverage;
-    case 3: return u.format3.get_coverage ();
-    default:return Null(Coverage);
-    }
-  }
-
-  inline bool would_apply (hb_would_apply_context_t *c) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (c);
-    case 2: return u.format2.would_apply (c);
-    case 3: return u.format3.would_apply (c);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->process (u.format1));
+    case 2: return TRACE_RETURN (c->process (u.format2));
+    case 3: return TRACE_RETURN (c->process (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     case 2: return TRACE_RETURN (u.format2.sanitize (c));
     case 3: return TRACE_RETURN (u.format3.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
@@ -1697,38 +1997,36 @@ struct ChainContext
   ChainContextFormat2	format2;
   ChainContextFormat3	format3;
   } u;
 };
 
 
 struct ExtensionFormat1
 {
-  friend struct Extension;
-
-  protected:
   inline unsigned int get_type (void) const { return extensionLookupType; }
   inline unsigned int get_offset (void) const { return extensionOffset; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
   protected:
   USHORT	format;			/* Format identifier. Set to 1. */
   USHORT	extensionLookupType;	/* Lookup type of subtable referenced
 					 * by ExtensionOffset (i.e. the
 					 * extension subtable). */
   ULONG		extensionOffset;	/* Offset to the extension subtable,
 					 * of lookup type subtable. */
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
+template <typename T>
 struct Extension
 {
   inline unsigned int get_type (void) const
   {
     switch (u.format) {
     case 1: return u.format1.get_type ();
     default:return 0;
     }
@@ -1736,25 +2034,47 @@ struct Extension
   inline unsigned int get_offset (void) const
   {
     switch (u.format) {
     case 1: return u.format1.get_offset ();
     default:return 0;
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    unsigned int offset = get_offset ();
+    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t process (context_t *c) const
+  {
+    return get_subtable<typename T::LookupSubTable> ().process (c, get_type ());
+  }
+
+  inline bool sanitize_self (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
     default:return TRACE_RETURN (true);
     }
   }
 
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    if (!sanitize_self (c)) return TRACE_RETURN (false);
+    unsigned int offset = get_offset ();
+    if (unlikely (!offset)) return TRACE_RETURN (true);
+    return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
+  }
+
   protected:
   union {
   USHORT		format;		/* Format identifier */
   ExtensionFormat1	format1;
   } u;
 };
 
 
@@ -1794,17 +2114,17 @@ struct GSUBGPOS
   { return (this+featureList).find_index (tag, index); }
 
   inline unsigned int get_lookup_count (void) const
   { return (this+lookupList).len; }
   inline const Lookup& get_lookup (unsigned int i) const
   { return (this+lookupList)[i]; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
 			 scriptList.sanitize (c, this) &&
 			 featureList.sanitize (c, this) &&
 			 lookupList.sanitize (c, this));
   }
 
   protected:
   FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
@@ -1815,12 +2135,12 @@ struct GSUBGPOS
 		featureList; 	/* FeatureList table */
   OffsetTo<LookupList>
 		lookupList; 	/* LookupList table */
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -44,16 +44,24 @@
 #define lig_props()		var1.u8[3] /* GSUB/GPOS ligature tracking */
 
 #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
 
 /*
  * GDEF
  */
 
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED	= 0x0001,
+  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 0x0002,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE	= 0x0004,
+  HB_OT_LAYOUT_GLYPH_PROPS_MARK		= 0x0008,
+  HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT	= 0x0010
+} hb_ot_layout_glyph_class_mask_t;
+
 
 
 /*
  * GSUB/GPOS
  */
 
 /* lig_id / lig_comp
  *
@@ -110,17 +118,17 @@ get_lig_comp (const hb_glyph_info_t &inf
   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_CLASS_LIGATURE) && is_a_ligature (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))
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -28,17 +28,16 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-layout-private.hh"
 
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-maxp-table.hh"
 
 #include <stdlib.h>
 #include <string.h>
 
 
 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
 
 hb_ot_layout_t *
@@ -66,19 +65,19 @@ hb_ot_layout_t *
   if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
 		(layout->gpos_lookup_count && !layout->gpos_digests)))
   {
     _hb_ot_layout_destroy (layout);
     return NULL;
   }
 
   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
-    layout->gsub->add_coverage (&layout->gsub_digests[i], i);
+    layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]);
   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
-    layout->gpos->add_coverage (&layout->gpos_digests[i], i);
+    layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]);
 
   return layout;
 }
 
 void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
 {
   hb_blob_destroy (layout->gdef_blob);
@@ -116,16 +115,30 @@ static inline const OT::GPOS&
  */
 
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face)
 {
   return _get_gdef (face).has_glyph_classes ();
 }
 
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
+			      hb_codepoint_t  glyph)
+{
+  return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
+}
+
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+				  hb_ot_layout_glyph_class_t  klass,
+				  hb_set_t                   *glyphs /* OUT */)
+{
+  return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
+}
 
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
 				unsigned int    start_offset,
 				unsigned int   *point_count /* IN/OUT */,
 				unsigned int   *point_array /* OUT */)
 {
@@ -382,16 +395,229 @@ 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);
 }
 
+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;
+
+  offset = 0;
+  do {
+    len = ARRAY_LENGTH (lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+				      table_tag,
+				      feature_index,
+				      offset, &len,
+				      lookup_indices);
+
+    for (unsigned int i = 0; i < len; i++)
+      lookup_indexes->add (lookup_indices[i]);
+
+    offset += len;
+  } while (len == ARRAY_LENGTH (lookup_indices));
+}
+
+static void
+_hb_ot_layout_collect_lookups_features (hb_face_t      *face,
+					hb_tag_t        table_tag,
+					unsigned int    script_index,
+					unsigned int    language_index,
+					const hb_tag_t *features,
+					hb_set_t       *lookup_indexes /* OUT */)
+{
+  unsigned int required_feature_index;
+  if (hb_ot_layout_language_get_required_feature_index (face,
+							table_tag,
+							script_index,
+							language_index,
+							&required_feature_index))
+    _hb_ot_layout_collect_lookups_lookups (face,
+					   table_tag,
+					   required_feature_index,
+					   lookup_indexes);
+
+  if (!features)
+  {
+    /* All features */
+    unsigned int feature_indices[32];
+    unsigned int offset, len;
+
+    offset = 0;
+    do {
+      len = ARRAY_LENGTH (feature_indices);
+      hb_ot_layout_language_get_feature_indexes (face,
+						 table_tag,
+						 script_index,
+						 language_index,
+						 offset, &len,
+						 feature_indices);
+
+      for (unsigned int i = 0; i < len; i++)
+	_hb_ot_layout_collect_lookups_lookups (face,
+					       table_tag,
+					       feature_indices[i],
+					       lookup_indexes);
+
+      offset += len;
+    } while (len == ARRAY_LENGTH (feature_indices));
+  }
+  else
+  {
+    for (; *features; features++)
+    {
+      unsigned int feature_index;
+      if (hb_ot_layout_language_find_feature (face,
+					      table_tag,
+					      script_index,
+					      language_index,
+					      *features,
+					      &feature_index))
+        _hb_ot_layout_collect_lookups_lookups (face,
+					       table_tag,
+					       feature_index,
+					       lookup_indexes);
+    }
+  }
+}
+
+static void
+_hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
+					 hb_tag_t        table_tag,
+					 unsigned int    script_index,
+					 const hb_tag_t *languages,
+					 const hb_tag_t *features,
+					 hb_set_t       *lookup_indexes /* OUT */)
+{
+  _hb_ot_layout_collect_lookups_features (face,
+					  table_tag,
+					  script_index,
+					  HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+					  features,
+					  lookup_indexes);
+
+  if (!languages)
+  {
+    /* All languages */
+    unsigned int count = hb_ot_layout_script_get_language_tags (face,
+								table_tag,
+								script_index,
+								0, NULL, NULL);
+    for (unsigned int language_index = 0; language_index < count; language_index++)
+      _hb_ot_layout_collect_lookups_features (face,
+					      table_tag,
+					      script_index,
+					      language_index,
+					      features,
+					      lookup_indexes);
+  }
+  else
+  {
+    for (; *languages; languages++)
+    {
+      unsigned int language_index;
+      if (hb_ot_layout_script_find_language (face,
+					     table_tag,
+					     script_index,
+					     *languages,
+					     &language_index))
+        _hb_ot_layout_collect_lookups_features (face,
+						table_tag,
+						script_index,
+						language_index,
+						features,
+						lookup_indexes);
+    }
+  }
+}
+
+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 */)
+{
+  if (!scripts)
+  {
+    /* All scripts */
+    unsigned int count = hb_ot_layout_table_get_script_tags (face,
+							     table_tag,
+							     0, NULL, NULL);
+    for (unsigned int script_index = 0; script_index < count; script_index++)
+      _hb_ot_layout_collect_lookups_languages (face,
+					       table_tag,
+					       script_index,
+					       languages,
+					       features,
+					       lookup_indexes);
+  }
+  else
+  {
+    for (; *scripts; scripts++)
+    {
+      unsigned int script_index;
+      if (hb_ot_layout_table_find_script (face,
+					  table_tag,
+					  *scripts,
+					  &script_index))
+        _hb_ot_layout_collect_lookups_languages (face,
+						 table_tag,
+						 script_index,
+						 languages,
+						 features,
+						 lookup_indexes);
+    }
+  }
+}
+
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+				    hb_tag_t      table_tag,
+				    unsigned int  lookup_index,
+				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
+				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
+				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
+				    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+
+  OT::hb_collect_glyphs_context_t c (face,
+				     glyphs_before,
+				     glyphs_input,
+				     glyphs_after,
+				     glyphs_output);
+
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+      l.collect_glyphs_lookup (&c);
+      return;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
+      l.collect_glyphs_lookup (&c);
+      return;
+    }
+  }
+}
+
 
 /*
  * OT::GSUB
  */
 
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
@@ -452,17 +678,20 @@ hb_ot_layout_substitute_finish (hb_font_
 }
 
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 				        unsigned int  lookup_index,
 				        hb_set_t     *glyphs)
 {
   OT::hb_closure_context_t c (face, glyphs);
-  _get_gsub (face).closure_lookup (&c, lookup_index);
+
+  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+
+  l.closure (&c);
 }
 
 /*
  * OT::GPOS
  */
 
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face)
@@ -491,8 +720,53 @@ hb_ot_layout_position_lookup (hb_font_t 
   return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
 }
 
 void
 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
 {
   OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
 }
+
+hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t    *face,
+			      unsigned int *design_size,       /* OUT.  May be NULL */
+			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
+			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+			      unsigned int *range_start,       /* OUT.  May be NULL */
+			      unsigned int *range_end          /* OUT.  May be NULL */)
+{
+  const OT::GPOS &gpos = _get_gpos (face);
+  const hb_tag_t tag = HB_TAG ('s','i','z','e');
+
+  unsigned int num_features = gpos.get_feature_count ();
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    if (tag == gpos.get_feature_tag (i))
+    {
+      const OT::Feature &f = gpos.get_feature (i);
+      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
+
+      if (params.designSize)
+      {
+#define PARAM(a, A) if (a) *a = params.A
+	PARAM (design_size, designSize);
+	PARAM (subfamily_id, subfamilyID);
+	PARAM (subfamily_name_id, subfamilyNameID);
+	PARAM (range_start, rangeStart);
+	PARAM (range_end, rangeEnd);
+#undef PARAM
+
+	return true;
+      }
+    }
+  }
+
+#define PARAM(a, A) if (a) *a = 0
+  PARAM (design_size, designSize);
+  PARAM (subfamily_id, subfamilyID);
+  PARAM (subfamily_name_id, subfamilyNameID);
+  PARAM (range_start, rangeStart);
+  PARAM (range_end, rangeEnd);
+#undef PARAM
+
+  return false;
+}
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -46,34 +46,31 @@ HB_BEGIN_DECLS
 /*
  * GDEF
  */
 
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
 typedef enum {
-  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0001,
-  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
-  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
-  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
-  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 1,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 2,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 3,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 4
 } hb_ot_layout_glyph_class_t;
 
-#ifdef HB_NOT_IMPLEMENTED
 hb_ot_layout_glyph_class_t
-Xhb_ot_layout_get_glyph_class (hb_face_t      *face,
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
 			      hb_codepoint_t  glyph);
-#endif
 
-#ifdef HB_NOT_IMPLEMENTED
-Xhb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
 				  hb_ot_layout_glyph_class_t  klass,
 				  hb_set_t                   *glyphs /* OUT */);
-#endif
 
 
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
 				unsigned int    start_offset,
@@ -177,41 +174,37 @@ 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 */);
 
-#ifdef HB_NOT_IMPLEMENTED
 void
-Xhb_ot_layout_collect_lookups (hb_face_t      *face,
+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 */);
-#endif
 
 void
 hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
 				  hb_tag_t         table_tag,
 				  hb_set_t        *lookup_indexes /* OUT */);
 
-#ifdef HB_NOT_IMPLEMENTED
 void
-Xhb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
 				    hb_tag_t      table_tag,
 				    unsigned int  lookup_index,
 				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
 				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
 				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
 				    hb_set_t     *glyphs_output  /* OUT. May be NULL */);
-#endif
 
 #ifdef HB_NOT_IMPLEMENTED
 typedef struct
 {
   const hb_codepoint_t *before,
   unsigned int          before_length,
   const hb_codepoint_t *input,
   unsigned int          input_length,
@@ -279,12 +272,22 @@ hb_ot_layout_has_positioning (hb_face_t 
 /* Note: You better have GDEF when using this API, or marks won't do much. */
 hb_bool_t
 Xhb_ot_layout_lookup_position (hb_font_t            *font,
 			      unsigned int          lookup_index,
 			      const hb_ot_layout_glyph_sequence_t *sequence,
 			      hb_glyph_position_t  *positions /* IN / OUT */);
 #endif
 
+/* Optical 'size' feature info.  Returns true if found.
+ * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t    *face,
+			      unsigned int *design_size,       /* OUT.  May be NULL */
+			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
+			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+			      unsigned int *range_start,       /* OUT.  May be NULL */
+			      unsigned int *range_end          /* OUT.  May be NULL */);
+
 
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
--- a/gfx/harfbuzz/src/hb-ot-maxp-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-maxp-table.hh
@@ -43,27 +43,27 @@ struct maxp
 {
   static const hb_tag_t Tag	= HB_OT_TAG_maxp;
 
   inline unsigned int get_num_glyphs (void) const {
     return numGlyphs;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
 			 likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000)));
   }
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
   protected:
   FixedVersion	version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000 or 0x00010000. */
   USHORT	numGlyphs;		/* The number of glyphs in the font. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_MAXP_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-name-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-name-table.hh
@@ -52,17 +52,17 @@ struct NameRecord
     ret = b->languageID.cmp (a->languageID);
     if (ret) return ret;
     ret = b->nameID.cmp (a->nameID);
     if (ret) return ret;
     return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
     return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
 
   USHORT	platformID;	/* Platform ID. */
   USHORT	encodingID;	/* Platform-specific encoding ID. */
   USHORT	languageID;	/* Language ID. */
   USHORT	nameID;		/* Name ID. */
@@ -94,26 +94,26 @@ struct name
       return 0;
 
     unsigned int length = MIN (buffer_length, (unsigned int) match->length);
     memcpy (buffer, (char *) this + stringOffset + match->offset, length);
     return length;
   }
 
   inline bool sanitize_records (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
     for (unsigned int i = 0; i < _count; i++)
       if (!nameRecord[i].sanitize (c, string_pool)) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
 			 likely (format == 0 || format == 1) &&
 			 c->check_array (nameRecord, nameRecord[0].static_size, count) &&
 			 sanitize_records (c));
   }
 
   /* We only implement format 0 for now. */
   protected:
@@ -121,12 +121,12 @@ struct name
   USHORT	count;			/* Number of name records. */
   Offset	stringOffset;		/* Offset to start of string storage (from start of table). */
   NameRecord	nameRecord[VAR];	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
 };
 
 
-} // namespace OT
+} /* namespace OT */
 
 
 #endif /* HB_OT_NAME_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -48,17 +48,17 @@ enum {
   FALLBACK_MEDI,
   FALLBACK_FINA,
   FALLBACK_ISOL,
   FALLBACK_RLIG,
   ARABIC_NUM_FALLBACK_FEATURES
 };
 
 static OT::SubstLookup *
-arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan,
+arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
 					  hb_font_t *font,
 					  unsigned int feature_index)
 {
   OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
   OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
   unsigned int num_glyphs = 0;
 
   /* Populate arrays */
@@ -98,17 +98,17 @@ arabic_fallback_synthesize_lookup_single
 				       num_glyphs);
   c.end_serialize ();
   /* TODO sanitize the results? */
 
   return ret ? c.copy<OT::SubstLookup> () : NULL;
 }
 
 static OT::SubstLookup *
-arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan,
+arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
 					    hb_font_t *font)
 {
   OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
   unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
   unsigned int num_first_glyphs = 0;
 
   /* We know that all our ligatures are 2-component */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
@@ -1,18 +1,18 @@
 /* == Start of generated table == */
 /*
  * The following table is generated by running:
  *
  *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
  *
  * on files with these headers:
  *
- * # ArabicShaping-6.1.0.txt
- * # Date: 2011-04-15, 23:16:00 GMT [KW]
+ * # ArabicShaping-6.2.0.txt
+ * # Date: 2012-05-15, 21:05:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
 #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 
 
 static const uint8_t joining_table[] =
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -300,17 +300,17 @@ arabic_joining (hb_buffer_t *buffer)
 
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 static void
 setup_masks_arabic (const hb_ot_shape_plan_t *plan,
 		    hb_buffer_t              *buffer,
-		    hb_font_t                *font)
+		    hb_font_t                *font HB_UNUSED)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   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()];
 }
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
@@ -85,124 +85,125 @@ normalization_preference_default (const 
 
 static bool
 compose_default (const hb_ot_shape_normalize_context_t *c,
 		 hb_codepoint_t  a,
 		 hb_codepoint_t  b,
 		 hb_codepoint_t *ab)
 {
   /* Hebrew presentation-form shaping.
-   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */
-  // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
-  // note that some letters do not have a dagesh presForm encoded
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
+   * Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
+   * Note that some letters do not have a dagesh presForm encoded.
+   */
   static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
-    0xFB30, // ALEF
-    0xFB31, // BET
-    0xFB32, // GIMEL
-    0xFB33, // DALET
-    0xFB34, // HE
-    0xFB35, // VAV
-    0xFB36, // ZAYIN
-    0, // HET
-    0xFB38, // TET
-    0xFB39, // YOD
-    0xFB3A, // FINAL KAF
-    0xFB3B, // KAF
-    0xFB3C, // LAMED
-    0, // FINAL MEM
-    0xFB3E, // MEM
-    0, // FINAL NUN
-    0xFB40, // NUN
-    0xFB41, // SAMEKH
-    0, // AYIN
-    0xFB43, // FINAL PE
-    0xFB44, // PE
-    0, // FINAL TSADI
-    0xFB46, // TSADI
-    0xFB47, // QOF
-    0xFB48, // RESH
-    0xFB49, // SHIN
-    0xFB4A // TAV
+    0xFB30, /* ALEF */
+    0xFB31, /* BET */
+    0xFB32, /* GIMEL */
+    0xFB33, /* DALET */
+    0xFB34, /* HE */
+    0xFB35, /* VAV */
+    0xFB36, /* ZAYIN */
+    0x0000, /* HET */
+    0xFB38, /* TET */
+    0xFB39, /* YOD */
+    0xFB3A, /* FINAL KAF */
+    0xFB3B, /* KAF */
+    0xFB3C, /* LAMED */
+    0x0000, /* FINAL MEM */
+    0xFB3E, /* MEM */
+    0x0000, /* FINAL NUN */
+    0xFB40, /* NUN */
+    0xFB41, /* SAMEKH */
+    0x0000, /* AYIN */
+    0xFB43, /* FINAL PE */
+    0xFB44, /* PE */
+    0x0000, /* FINAL TSADI */
+    0xFB46, /* TSADI */
+    0xFB47, /* QOF */
+    0xFB48, /* RESH */
+    0xFB49, /* SHIN */
+    0xFB4A /* TAV */
   };
 
   bool found = c->unicode->compose (a, b, ab);
 
   if (!found && (b & ~0x7F) == 0x0580) {
-      // special-case Hebrew presentation forms that are excluded from
-      // standard normalization, but wanted for old fonts
+      /* Special-case Hebrew presentation forms that are excluded from
+       * standard normalization, but wanted for old fonts. */
       switch (b) {
-      case 0x05B4: // HIRIQ
-	  if (a == 0x05D9) { // YOD
+      case 0x05B4: /* HIRIQ */
+	  if (a == 0x05D9) { /* YOD */
 	      *ab = 0xFB1D;
 	      found = true;
 	  }
 	  break;
-      case 0x05B7: // patah
-	  if (a == 0x05F2) { // YIDDISH YOD YOD
+      case 0x05B7: /* patah */
+	  if (a == 0x05F2) { /* YIDDISH YOD YOD */
 	      *ab = 0xFB1F;
 	      found = true;
-	  } else if (a == 0x05D0) { // ALEF
+	  } else if (a == 0x05D0) { /* ALEF */
 	      *ab = 0xFB2E;
 	      found = true;
 	  }
 	  break;
-      case 0x05B8: // QAMATS
-	  if (a == 0x05D0) { // ALEF
+      case 0x05B8: /* QAMATS */
+	  if (a == 0x05D0) { /* ALEF */
 	      *ab = 0xFB2F;
 	      found = true;
 	  }
 	  break;
-      case 0x05B9: // HOLAM
-	  if (a == 0x05D5) { // VAV
+      case 0x05B9: /* HOLAM */
+	  if (a == 0x05D5) { /* VAV */
 	      *ab = 0xFB4B;
 	      found = true;
 	  }
 	  break;
-      case 0x05BC: // DAGESH
+      case 0x05BC: /* DAGESH */
 	  if (a >= 0x05D0 && a <= 0x05EA) {
 	      *ab = sDageshForms[a - 0x05D0];
 	      found = (*ab != 0);
-	  } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
+	  } else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
 	      *ab = 0xFB2C;
 	      found = true;
-	  } else if (a == 0xFB2B) { // SHIN WITH SIN DOT
+	  } else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
 	      *ab = 0xFB2D;
 	      found = true;
 	  }
 	  break;
-      case 0x05BF: // RAFE
+      case 0x05BF: /* RAFE */
 	  switch (a) {
-	  case 0x05D1: // BET
+	  case 0x05D1: /* BET */
 	      *ab = 0xFB4C;
 	      found = true;
 	      break;
-	  case 0x05DB: // KAF
+	  case 0x05DB: /* KAF */
 	      *ab = 0xFB4D;
 	      found = true;
 	      break;
-	  case 0x05E4: // PE
+	  case 0x05E4: /* PE */
 	      *ab = 0xFB4E;
 	      found = true;
 	      break;
 	  }
 	  break;
-      case 0x05C1: // SHIN DOT
-	  if (a == 0x05E9) { // SHIN
+      case 0x05C1: /* SHIN DOT */
+	  if (a == 0x05E9) { /* SHIN */
 	      *ab = 0xFB2A;
 	      found = true;
-	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
+	  } else if (a == 0xFB49) { /* SHIN WITH DAGESH */
 	      *ab = 0xFB2C;
 	      found = true;
 	  }
 	  break;
-      case 0x05C2: // SIN DOT
-	  if (a == 0x05E9) { // SHIN
+      case 0x05C2: /* SIN DOT */
+	  if (a == 0x05E9) { /* SHIN */
 	      *ab = 0xFB2B;
 	      found = true;
-	  } else if (a == 0xFB49) { // SHIN WITH DAGESH
+	  } else if (a == 0xFB49) { /* SHIN WITH DAGESH */
 	      *ab = 0xFB2D;
 	      found = true;
 	  }
 	  break;
       }
   }
 
   return found;
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -46,55 +46,62 @@ static const unsigned char _indic_syllab
 	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, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 
 	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 
 	7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
 	6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 
-	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 
-	3u, 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, 
+	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, 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, 
+	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, 4u, 14u, 3u, 14u, 4u, 14u, 3u, 14u, 
+	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, 3u, 14u, 
-	1u, 16u, 3u, 17u, 1u, 16u, 0
+	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
 };
 
 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, 
@@ -105,55 +112,62 @@ static const char _indic_syllable_machin
 	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, 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, 
-	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, 
+	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, 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, 
+	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, 11, 12, 11, 12, 
+	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, 12, 
-	16, 15, 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
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
 	0, 17, 19, 23, 27, 29, 33, 37, 
 	39, 43, 47, 49, 53, 57, 59, 61, 
 	63, 65, 70, 72, 74, 79, 81, 83, 
 	88, 90, 92, 104, 116, 128, 140, 152, 
 	164, 176, 188, 200, 212, 229, 231, 235, 
@@ -165,54 +179,61 @@ static const short _indic_syllable_machi
 	463, 467, 471, 473, 477, 481, 483, 485, 
 	487, 489, 494, 496, 498, 503, 505, 507, 
 	512, 514, 516, 528, 540, 552, 564, 576, 
 	588, 600, 612, 624, 641, 643, 647, 651, 
 	653, 657, 661, 663, 667, 671, 673, 677, 
 	681, 683, 685, 687, 689, 694, 696, 698, 
 	703, 705, 707, 712, 714, 716, 728, 740, 
 	752, 764, 776, 788, 800, 812, 824, 836, 
-	853, 869, 882, 894, 911, 927, 940, 952, 
-	969, 985, 998, 1010, 1027, 1043, 1056, 1068, 
-	1085, 1101, 1114, 1126, 1137, 1145, 1151, 1153, 
-	1155, 1171, 1179, 1182, 1190, 1202, 1215, 1228, 
-	1240, 1251, 1264, 1276, 1287, 1300, 1312, 1323, 
-	1336, 1348, 1358, 1371, 1383, 1400, 1413, 1426, 
-	1443, 1460, 1477, 1494, 1511, 1524, 1537, 1554, 
-	1571, 1588, 1605, 1622, 1635, 1648, 1665, 1682, 
-	1699, 1716, 1733, 1746, 1759, 1776, 1793, 1810, 
-	1827, 1844, 1857, 1870, 1883, 1896, 1908, 1925, 
-	1941, 1954, 1966, 1983, 1999, 2012, 2024, 2041, 
-	2057, 2070, 2082, 2099, 2115, 2128, 2140, 2151, 
-	2159, 2165, 2167, 2169, 2185, 2193, 2196, 2204, 
-	2216, 2229, 2242, 2254, 2265, 2278, 2290, 2301, 
-	2314, 2326, 2337, 2350, 2362, 2372, 2385, 2402, 
-	2415, 2428, 2445, 2462, 2479, 2496, 2513, 2526, 
-	2539, 2556, 2573, 2590, 2607, 2624, 2637, 2650, 
-	2667, 2684, 2701, 2718, 2735, 2748, 2761, 2778, 
-	2795, 2812, 2829, 2841, 2858, 2871, 2884, 2896, 
-	2913, 2929, 2942, 2954, 2971, 2987, 3000, 3012, 
-	3029, 3045, 3058, 3070, 3087, 3103, 3116, 3128, 
-	3139, 3147, 3153, 3155, 3157, 3173, 3181, 3184, 
-	3192, 3204, 3217, 3230, 3242, 3253, 3266, 3278, 
-	3289, 3302, 3314, 3325, 3338, 3350, 3360, 3373, 
-	3390, 3403, 3416, 3433, 3450, 3467, 3484, 3501, 
-	3514, 3527, 3544, 3561, 3578, 3595, 3612, 3625, 
-	3638, 3655, 3672, 3689, 3706, 3723, 3736, 3749, 
-	3766, 3783, 3800, 3817, 3834, 3846, 3859, 3871, 
-	3884, 3897, 3909, 3926, 3942, 3955, 3967, 3984, 
-	4000, 4013, 4025, 4042, 4058, 4071, 4083, 4100, 
-	4116, 4129, 4141, 4152, 4160, 4166, 4168, 4170, 
-	4186, 4194, 4197, 4205, 4217, 4230, 4243, 4255, 
-	4266, 4279, 4291, 4302, 4315, 4327, 4338, 4351, 
-	4363, 4373, 4386, 4403, 4416, 4429, 4446, 4463, 
-	4480, 4497, 4514, 4527, 4540, 4557, 4574, 4591, 
-	4608, 4625, 4638, 4651, 4668, 4685, 4702, 4719, 
-	4736, 4749, 4762, 4779, 4796, 4813, 4830, 4847, 
-	4860, 4877, 4893
+	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
 };
 
 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, 
@@ -280,17 +301,17 @@ static const short _indic_syllable_machi
 	105, 80, 80, 81, 76, 76, 76, 76, 
 	76, 106, 105, 76, 107, 80, 80, 81, 
 	76, 76, 76, 76, 76, 76, 107, 76, 
 	107, 80, 80, 81, 76, 76, 76, 76, 
 	76, 108, 107, 76, 109, 80, 80, 81, 
 	76, 76, 76, 76, 76, 76, 109, 76, 
 	109, 80, 80, 81, 76, 76, 76, 76, 
 	76, 110, 109, 76, 111, 80, 80, 81, 
-	76, 76, 76, 76, 76, 76, 111, 76, 
+	82, 82, 82, 82, 82, 82, 111, 82, 
 	111, 80, 80, 81, 76, 76, 76, 76, 
 	76, 112, 111, 76, 113, 80, 80, 81, 
 	76, 76, 76, 76, 76, 76, 113, 76, 
 	115, 116, 114, 114, 114, 114, 114, 114, 
 	114, 114, 114, 114, 114, 114, 114, 115, 
 	114, 117, 114, 118, 118, 119, 114, 120, 
 	120, 119, 114, 119, 114, 121, 121, 122, 
 	114, 123, 123, 122, 114, 122, 114, 124, 
@@ -310,587 +331,650 @@ static const short _indic_syllable_machi
 	114, 114, 114, 114, 114, 114, 146, 114, 
 	146, 118, 118, 119, 114, 114, 114, 114, 
 	114, 147, 146, 114, 148, 118, 118, 119, 
 	114, 114, 114, 114, 114, 114, 148, 114, 
 	148, 118, 118, 119, 114, 114, 114, 114, 
 	114, 149, 148, 114, 150, 118, 118, 119, 
 	114, 114, 114, 114, 114, 114, 150, 114, 
 	150, 118, 118, 119, 114, 114, 114, 114, 
-	114, 151, 150, 114, 153, 154, 155, 156, 
-	157, 158, 81, 159, 160, 152, 161, 161, 
-	162, 163, 164, 165, 152, 167, 168, 169, 
-	170, 5, 171, 172, 173, 166, 166, 37, 
-	174, 166, 166, 153, 166, 175, 168, 176, 
-	176, 5, 171, 172, 173, 166, 166, 166, 
-	174, 166, 168, 176, 176, 5, 171, 172, 
-	173, 166, 166, 166, 174, 166, 177, 166, 
-	166, 166, 18, 178, 166, 171, 172, 166, 
-	166, 166, 166, 179, 166, 177, 166, 180, 
-	181, 182, 183, 5, 171, 172, 173, 166, 
-	166, 35, 184, 166, 166, 177, 166, 185, 
-	181, 186, 186, 5, 171, 172, 173, 166, 
-	166, 166, 184, 166, 181, 186, 186, 5, 
-	171, 172, 173, 166, 166, 166, 184, 166, 
-	187, 166, 166, 166, 18, 188, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 187, 
-	166, 189, 190, 191, 192, 5, 171, 172, 
-	173, 166, 166, 33, 193, 166, 166, 187, 
-	166, 194, 190, 195, 195, 5, 171, 172, 
-	173, 166, 166, 166, 193, 166, 190, 195, 
-	195, 5, 171, 172, 173, 166, 166, 166, 
-	193, 166, 196, 166, 166, 166, 18, 197, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 196, 166, 198, 199, 200, 201, 5, 
-	171, 172, 173, 166, 166, 31, 202, 166, 
-	166, 196, 166, 203, 199, 204, 204, 5, 
-	171, 172, 173, 166, 166, 166, 202, 166, 
-	199, 204, 204, 5, 171, 172, 173, 166, 
-	166, 166, 202, 166, 205, 166, 166, 166, 
-	18, 206, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 205, 166, 207, 208, 209, 
-	210, 5, 171, 172, 173, 166, 166, 29, 
-	211, 166, 166, 205, 166, 212, 208, 213, 
-	213, 5, 171, 172, 173, 166, 166, 166, 
-	211, 166, 208, 213, 213, 5, 171, 172, 
-	173, 166, 166, 166, 211, 166, 18, 214, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 215, 166, 166, 166, 172, 166, 172, 
-	166, 216, 166, 217, 166, 218, 219, 166, 
-	171, 172, 166, 166, 166, 3, 166, 166, 
-	166, 1, 166, 2, 166, 166, 166, 166, 
-	171, 172, 166, 171, 172, 166, 217, 166, 
-	166, 166, 166, 171, 172, 166, 217, 166, 
-	218, 166, 166, 171, 172, 166, 166, 166, 
-	3, 166, 18, 166, 220, 220, 5, 171, 
-	172, 166, 166, 166, 166, 179, 166, 221, 
-	27, 222, 223, 8, 171, 172, 166, 166, 
-	166, 166, 179, 166, 27, 222, 223, 8, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	222, 222, 8, 171, 172, 166, 166, 166, 
-	166, 179, 166, 224, 24, 225, 226, 11, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	24, 225, 226, 11, 171, 172, 166, 166, 
-	166, 166, 179, 166, 225, 225, 11, 171, 
-	172, 166, 166, 166, 166, 179, 166, 227, 
-	21, 228, 229, 14, 171, 172, 166, 166, 
-	166, 166, 179, 166, 21, 228, 229, 14, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	228, 228, 14, 171, 172, 166, 166, 166, 
-	166, 179, 166, 230, 18, 166, 231, 166, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	18, 166, 231, 166, 171, 172, 166, 166, 
-	166, 166, 179, 166, 232, 166, 171, 172, 
-	166, 166, 166, 166, 179, 166, 18, 166, 
-	166, 166, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 208, 213, 213, 5, 171, 
-	172, 166, 166, 166, 166, 211, 166, 1, 
-	2, 166, 166, 18, 214, 166, 171, 172, 
-	166, 166, 166, 166, 179, 166, 1, 166, 
-	207, 208, 213, 213, 5, 171, 172, 173, 
-	166, 166, 166, 211, 166, 207, 208, 209, 
-	213, 5, 171, 172, 173, 166, 166, 29, 
-	211, 166, 205, 166, 233, 166, 220, 220, 
-	5, 171, 172, 166, 166, 166, 166, 179, 
-	166, 205, 166, 205, 166, 166, 166, 166, 
-	166, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 205, 166, 205, 166, 166, 166, 
-	166, 234, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 205, 166, 205, 166, 233, 
-	166, 166, 166, 166, 171, 172, 166, 166, 
-	166, 166, 179, 166, 205, 166, 205, 2, 
-	166, 166, 18, 206, 166, 171, 172, 166, 
-	166, 166, 166, 179, 166, 205, 166, 198, 
-	199, 204, 204, 5, 171, 172, 173, 166, 
-	166, 166, 202, 166, 198, 199, 200, 204, 
-	5, 171, 172, 173, 166, 166, 31, 202, 
-	166, 196, 166, 235, 166, 220, 220, 5, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	196, 166, 196, 166, 166, 166, 166, 166, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 196, 166, 196, 166, 166, 166, 166, 
-	236, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 196, 166, 196, 166, 235, 166, 
-	166, 166, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 196, 166, 196, 2, 166, 
-	166, 18, 197, 166, 171, 172, 166, 166, 
-	166, 166, 179, 166, 196, 166, 189, 190, 
-	195, 195, 5, 171, 172, 173, 166, 166, 
-	166, 193, 166, 189, 190, 191, 195, 5, 
-	171, 172, 173, 166, 166, 33, 193, 166, 
-	187, 166, 237, 166, 220, 220, 5, 171, 
-	172, 166, 166, 166, 166, 179, 166, 187, 
-	166, 187, 166, 166, 166, 166, 166, 166, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	187, 166, 187, 166, 166, 166, 166, 238, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 187, 166, 187, 166, 237, 166, 166, 
-	166, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 187, 166, 187, 2, 166, 166, 
-	18, 188, 166, 171, 172, 166, 166, 166, 
-	166, 179, 166, 187, 166, 180, 181, 186, 
-	186, 5, 171, 172, 173, 166, 166, 166, 
-	184, 166, 180, 181, 182, 186, 5, 171, 
-	172, 173, 166, 166, 35, 184, 166, 177, 
-	166, 239, 166, 220, 220, 5, 171, 172, 
-	166, 166, 166, 166, 179, 166, 177, 166, 
-	177, 166, 166, 166, 166, 166, 166, 171, 
-	172, 166, 166, 166, 166, 179, 166, 177, 
-	166, 177, 166, 166, 166, 166, 240, 166, 
-	171, 172, 166, 166, 166, 166, 179, 166, 
-	177, 166, 177, 166, 239, 166, 166, 166, 
-	166, 171, 172, 166, 166, 166, 166, 179, 
-	166, 177, 166, 177, 2, 166, 166, 18, 
-	178, 166, 171, 172, 166, 166, 166, 166, 
-	179, 166, 177, 166, 167, 168, 176, 176, 
-	5, 171, 172, 173, 166, 166, 166, 174, 
-	166, 167, 168, 169, 176, 5, 171, 172, 
-	173, 166, 166, 37, 174, 166, 242, 243, 
-	244, 245, 43, 246, 247, 241, 241, 241, 
-	75, 248, 241, 249, 243, 250, 245, 43, 
-	246, 247, 241, 241, 241, 241, 248, 241, 
-	243, 250, 245, 43, 246, 247, 241, 241, 
-	241, 241, 248, 241, 251, 241, 241, 241, 
-	56, 252, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 251, 241, 254, 255, 256, 
-	257, 43, 246, 247, 241, 241, 241, 73, 
-	258, 241, 241, 251, 241, 259, 255, 260, 
-	260, 43, 246, 247, 241, 241, 241, 241, 
-	258, 241, 255, 260, 260, 43, 246, 247, 
-	241, 241, 241, 241, 258, 241, 261, 241, 
-	241, 241, 56, 262, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 261, 241, 263, 
-	264, 265, 266, 43, 246, 247, 241, 241, 
-	241, 71, 267, 241, 241, 261, 241, 268, 
-	264, 269, 269, 43, 246, 247, 241, 241, 
-	241, 241, 267, 241, 264, 269, 269, 43, 
-	246, 247, 241, 241, 241, 241, 267, 241, 
-	270, 241, 241, 241, 56, 271, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 270, 
-	241, 272, 273, 274, 275, 43, 246, 247, 
-	241, 241, 241, 69, 276, 241, 241, 270, 
-	241, 277, 273, 278, 278, 43, 246, 247, 
-	241, 241, 241, 241, 276, 241, 273, 278, 
-	278, 43, 246, 247, 241, 241, 241, 241, 
-	276, 241, 279, 241, 241, 241, 56, 280, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 279, 241, 281, 282, 283, 284, 43, 
-	246, 247, 241, 241, 241, 67, 285, 241, 
-	241, 279, 241, 286, 282, 287, 287, 43, 
-	246, 247, 241, 241, 241, 241, 285, 241, 
-	282, 287, 287, 43, 246, 247, 241, 241, 
-	241, 241, 285, 241, 56, 288, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 289, 
-	241, 241, 241, 247, 241, 247, 241, 290, 
-	241, 291, 241, 292, 293, 241, 246, 247, 
-	241, 241, 241, 41, 241, 241, 241, 39, 
-	241, 40, 241, 241, 241, 241, 246, 247, 
-	241, 246, 247, 241, 291, 241, 241, 241, 
-	241, 246, 247, 241, 291, 241, 292, 241, 
-	241, 246, 247, 241, 241, 241, 41, 241, 
-	56, 241, 294, 294, 43, 246, 247, 241, 
-	241, 241, 241, 253, 241, 295, 65, 296, 
-	297, 46, 246, 247, 241, 241, 241, 241, 
-	253, 241, 65, 296, 297, 46, 246, 247, 
-	241, 241, 241, 241, 253, 241, 296, 296, 
-	46, 246, 247, 241, 241, 241, 241, 253, 
-	241, 298, 62, 299, 300, 49, 246, 247, 
-	241, 241, 241, 241, 253, 241, 62, 299, 
-	300, 49, 246, 247, 241, 241, 241, 241, 
-	253, 241, 299, 299, 49, 246, 247, 241, 
-	241, 241, 241, 253, 241, 301, 59, 302, 
-	303, 52, 246, 247, 241, 241, 241, 241, 
-	253, 241, 59, 302, 303, 52, 246, 247, 
-	241, 241, 241, 241, 253, 241, 302, 302, 
-	52, 246, 247, 241, 241, 241, 241, 253, 
-	241, 304, 56, 241, 305, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 56, 241, 
-	305, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 306, 241, 246, 247, 241, 241, 
-	241, 241, 253, 241, 56, 241, 241, 241, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 39, 40, 241, 241, 56, 288, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	39, 241, 281, 282, 287, 287, 43, 246, 
-	247, 241, 241, 241, 241, 285, 241, 281, 
-	282, 283, 287, 43, 246, 247, 241, 241, 
-	241, 67, 285, 241, 279, 241, 307, 241, 
-	294, 294, 43, 246, 247, 241, 241, 241, 
-	241, 253, 241, 279, 241, 279, 241, 241, 
-	241, 241, 241, 241, 246, 247, 241, 241, 
-	241, 241, 253, 241, 279, 241, 279, 241, 
-	241, 241, 241, 308, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 279, 241, 279, 
-	241, 307, 241, 241, 241, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 279, 241, 
-	279, 40, 241, 241, 56, 280, 241, 246, 
-	247, 241, 241, 241, 241, 253, 241, 279, 
-	241, 272, 273, 278, 278, 43, 246, 247, 
-	241, 241, 241, 241, 276, 241, 272, 273, 
-	274, 278, 43, 246, 247, 241, 241, 241, 
-	69, 276, 241, 270, 241, 309, 241, 294, 
-	294, 43, 246, 247, 241, 241, 241, 241, 
-	253, 241, 270, 241, 270, 241, 241, 241, 
-	241, 241, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 270, 241, 270, 241, 241, 
-	241, 241, 310, 241, 246, 247, 241, 241, 
-	241, 241, 253, 241, 270, 241, 270, 241, 
-	309, 241, 241, 241, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 270, 241, 270, 
-	40, 241, 241, 56, 271, 241, 246, 247, 
-	241, 241, 241, 241, 253, 241, 270, 241, 
-	263, 264, 269, 269, 43, 246, 247, 241, 
-	241, 241, 241, 267, 241, 263, 264, 265, 
-	269, 43, 246, 247, 241, 241, 241, 71, 
-	267, 241, 261, 241, 311, 241, 294, 294, 
-	43, 246, 247, 241, 241, 241, 241, 253, 
-	241, 261, 241, 261, 241, 241, 241, 241, 
-	241, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 261, 241, 261, 241, 241, 241, 
-	241, 312, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 261, 241, 261, 241, 311, 
-	241, 241, 241, 241, 246, 247, 241, 241, 
-	241, 241, 253, 241, 261, 241, 261, 40, 
-	241, 241, 56, 262, 241, 246, 247, 241, 
-	241, 241, 241, 253, 241, 261, 241, 254, 
-	255, 260, 260, 43, 246, 247, 241, 241, 
-	241, 241, 258, 241, 254, 255, 256, 260, 
-	43, 246, 247, 241, 241, 241, 73, 258, 
-	241, 251, 241, 313, 241, 294, 294, 43, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	251, 241, 251, 241, 241, 241, 241, 241, 
-	241, 246, 247, 241, 241, 241, 241, 253, 
-	241, 251, 241, 251, 241, 241, 241, 241, 
-	314, 241, 246, 247, 241, 241, 241, 241, 
-	253, 241, 251, 241, 251, 241, 313, 241, 
-	241, 241, 241, 246, 247, 241, 241, 241, 
-	241, 253, 241, 251, 241, 74, 42, 42, 
-	43, 241, 241, 241, 241, 241, 241, 74, 
-	241, 251, 40, 241, 241, 56, 252, 241, 
-	246, 247, 241, 241, 241, 241, 253, 241, 
-	251, 241, 242, 243, 250, 245, 43, 246, 
-	247, 241, 241, 241, 241, 248, 241, 316, 
-	156, 317, 317, 81, 159, 160, 315, 315, 
-	315, 315, 163, 315, 156, 317, 317, 81, 
-	159, 160, 315, 315, 315, 315, 163, 315, 
-	318, 315, 315, 315, 95, 319, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 318, 
-	315, 321, 322, 323, 324, 81, 159, 160, 
-	315, 315, 315, 112, 325, 315, 315, 318, 
-	315, 326, 322, 327, 327, 81, 159, 160, 
-	315, 315, 315, 315, 325, 315, 322, 327, 
-	327, 81, 159, 160, 315, 315, 315, 315, 
-	325, 315, 328, 315, 315, 315, 95, 329, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 328, 315, 330, 331, 332, 333, 81, 
-	159, 160, 315, 315, 315, 110, 334, 315, 
-	315, 328, 315, 335, 331, 336, 336, 81, 
-	159, 160, 315, 315, 315, 315, 334, 315, 
-	331, 336, 336, 81, 159, 160, 315, 315, 
-	315, 315, 334, 315, 337, 315, 315, 315, 
-	95, 338, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 337, 315, 339, 340, 341, 
-	342, 81, 159, 160, 315, 315, 315, 108, 
-	343, 315, 315, 337, 315, 344, 340, 345, 
-	345, 81, 159, 160, 315, 315, 315, 315, 
-	343, 315, 340, 345, 345, 81, 159, 160, 
-	315, 315, 315, 315, 343, 315, 346, 315, 
-	315, 315, 95, 347, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 346, 315, 348, 
-	349, 350, 351, 81, 159, 160, 315, 315, 
-	315, 106, 352, 315, 315, 346, 315, 353, 
-	349, 354, 354, 81, 159, 160, 315, 315, 
-	315, 315, 352, 315, 349, 354, 354, 81, 
-	159, 160, 315, 315, 315, 315, 352, 315, 
-	95, 355, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 356, 315, 315, 315, 160, 
-	315, 160, 315, 357, 315, 358, 315, 359, 
-	360, 315, 159, 160, 315, 315, 315, 79, 
-	315, 315, 315, 77, 315, 78, 315, 315, 
-	315, 315, 159, 160, 315, 159, 160, 315, 
-	358, 315, 315, 315, 315, 159, 160, 315, 
-	358, 315, 359, 315, 315, 159, 160, 315, 
-	315, 315, 79, 315, 95, 315, 361, 361, 
-	81, 159, 160, 315, 315, 315, 315, 320, 
-	315, 362, 104, 363, 364, 85, 159, 160, 
-	315, 315, 315, 315, 320, 315, 104, 363, 
-	364, 85, 159, 160, 315, 315, 315, 315, 
-	320, 315, 363, 363, 85, 159, 160, 315, 
-	315, 315, 315, 320, 315, 365, 101, 366, 
-	367, 88, 159, 160, 315, 315, 315, 315, 
-	320, 315, 101, 366, 367, 88, 159, 160, 
-	315, 315, 315, 315, 320, 315, 366, 366, 
-	88, 159, 160, 315, 315, 315, 315, 320, 
-	315, 368, 98, 369, 370, 91, 159, 160, 
-	315, 315, 315, 315, 320, 315, 98, 369, 
-	370, 91, 159, 160, 315, 315, 315, 315, 
-	320, 315, 369, 369, 91, 159, 160, 315, 
-	315, 315, 315, 320, 315, 371, 95, 315, 
-	372, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 95, 315, 372, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 373, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	95, 315, 315, 315, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 77, 78, 315, 
-	315, 95, 355, 315, 159, 160, 315, 315, 
-	315, 315, 320, 315, 77, 315, 348, 349, 
-	354, 354, 81, 159, 160, 315, 315, 315, 
-	315, 352, 315, 348, 349, 350, 354, 81, 
-	159, 160, 315, 315, 315, 106, 352, 315, 
-	346, 315, 374, 315, 361, 361, 81, 159, 
-	160, 315, 315, 315, 315, 320, 315, 346, 
-	315, 346, 315, 315, 315, 315, 315, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	346, 315, 346, 315, 315, 315, 315, 375, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 346, 315, 346, 315, 374, 315, 315, 
-	315, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 346, 315, 346, 78, 315, 315, 
-	95, 347, 315, 159, 160, 315, 315, 315, 
-	315, 320, 315, 346, 315, 339, 340, 345, 
-	345, 81, 159, 160, 315, 315, 315, 315, 
-	343, 315, 339, 340, 341, 345, 81, 159, 
-	160, 315, 315, 315, 108, 343, 315, 337, 
-	315, 376, 315, 361, 361, 81, 159, 160, 
-	315, 315, 315, 315, 320, 315, 337, 315, 
-	337, 315, 315, 315, 315, 315, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 337, 
-	315, 337, 315, 315, 315, 315, 377, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	337, 315, 337, 315, 376, 315, 315, 315, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 337, 315, 337, 78, 315, 315, 95, 
-	338, 315, 159, 160, 315, 315, 315, 315, 
-	320, 315, 337, 315, 330, 331, 336, 336, 
-	81, 159, 160, 315, 315, 315, 315, 334, 
-	315, 330, 331, 332, 336, 81, 159, 160, 
-	315, 315, 315, 110, 334, 315, 328, 315, 
-	378, 315, 361, 361, 81, 159, 160, 315, 
-	315, 315, 315, 320, 315, 328, 315, 328, 
-	315, 315, 315, 315, 315, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 328, 315, 
-	328, 315, 315, 315, 315, 379, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 328, 
-	315, 328, 315, 378, 315, 315, 315, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	328, 315, 328, 78, 315, 315, 95, 329, 
-	315, 159, 160, 315, 315, 315, 315, 320, 
-	315, 328, 315, 321, 322, 327, 327, 81, 
-	159, 160, 315, 315, 315, 315, 325, 315, 
-	321, 322, 323, 327, 81, 159, 160, 315, 
-	315, 315, 112, 325, 315, 318, 315, 380, 
-	315, 361, 361, 81, 159, 160, 315, 315, 
-	315, 315, 320, 315, 318, 315, 318, 315, 
-	315, 315, 315, 315, 315, 159, 160, 315, 
-	315, 315, 315, 320, 315, 318, 315, 318, 
-	315, 315, 315, 315, 381, 315, 159, 160, 
-	315, 315, 315, 315, 320, 315, 318, 315, 
-	318, 315, 380, 315, 315, 315, 315, 159, 
-	160, 315, 315, 315, 315, 320, 315, 318, 
-	315, 318, 78, 315, 315, 95, 319, 315, 
-	159, 160, 315, 315, 315, 315, 320, 315, 
-	318, 315, 113, 80, 80, 81, 382, 382, 
-	382, 382, 382, 162, 113, 382, 155, 156, 
-	317, 317, 81, 159, 160, 315, 315, 315, 
-	315, 163, 315, 113, 80, 80, 81, 382, 
-	382, 382, 382, 382, 382, 113, 382, 384, 
-	385, 386, 387, 119, 388, 389, 383, 383, 
-	383, 151, 390, 383, 391, 385, 387, 387, 
-	119, 388, 389, 383, 383, 383, 383, 390, 
-	383, 385, 387, 387, 119, 388, 389, 383, 
-	383, 383, 383, 390, 383, 392, 383, 383, 
-	383, 132, 393, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 392, 383, 395, 396, 
-	397, 398, 119, 388, 389, 383, 383, 383, 
-	149, 399, 383, 383, 392, 383, 400, 396, 
-	401, 401, 119, 388, 389, 383, 383, 383, 
-	383, 399, 383, 396, 401, 401, 119, 388, 
-	389, 383, 383, 383, 383, 399, 383, 402, 
-	383, 383, 383, 132, 403, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 402, 383, 
-	404, 405, 406, 407, 119, 388, 389, 383, 
-	383, 383, 147, 408, 383, 383, 402, 383, 
-	409, 405, 410, 410, 119, 388, 389, 383, 
-	383, 383, 383, 408, 383, 405, 410, 410, 
-	119, 388, 389, 383, 383, 383, 383, 408, 
-	383, 411, 383, 383, 383, 132, 412, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	411, 383, 413, 414, 415, 416, 119, 388, 
-	389, 383, 383, 383, 145, 417, 383, 383, 
-	411, 383, 418, 414, 419, 419, 119, 388, 
-	389, 383, 383, 383, 383, 417, 383, 414, 
-	419, 419, 119, 388, 389, 383, 383, 383, 
-	383, 417, 383, 420, 383, 383, 383, 132, 
-	421, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 420, 383, 422, 423, 424, 425, 
-	119, 388, 389, 383, 383, 383, 143, 426, 
-	383, 383, 420, 383, 427, 423, 428, 428, 
-	119, 388, 389, 383, 383, 383, 383, 426, 
-	383, 423, 428, 428, 119, 388, 389, 383, 
-	383, 383, 383, 426, 383, 132, 429, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	430, 383, 383, 383, 389, 383, 389, 383, 
-	431, 383, 432, 383, 433, 434, 383, 388, 
-	389, 383, 383, 383, 117, 383, 383, 383, 
-	115, 383, 116, 383, 383, 383, 383, 388, 
-	389, 383, 388, 389, 383, 432, 383, 383, 
-	383, 383, 388, 389, 383, 432, 383, 433, 
-	383, 383, 388, 389, 383, 383, 383, 117, 
-	383, 132, 383, 435, 435, 119, 388, 389, 
-	383, 383, 383, 383, 394, 383, 436, 141, 
-	437, 438, 122, 388, 389, 383, 383, 383, 
-	383, 394, 383, 141, 437, 438, 122, 388, 
-	389, 383, 383, 383, 383, 394, 383, 437, 
-	437, 122, 388, 389, 383, 383, 383, 383, 
-	394, 383, 439, 138, 440, 441, 125, 388, 
-	389, 383, 383, 383, 383, 394, 383, 138, 
-	440, 441, 125, 388, 389, 383, 383, 383, 
-	383, 394, 383, 440, 440, 125, 388, 389, 
-	383, 383, 383, 383, 394, 383, 442, 135, 
-	443, 444, 128, 388, 389, 383, 383, 383, 
-	383, 394, 383, 135, 443, 444, 128, 388, 
-	389, 383, 383, 383, 383, 394, 383, 443, 
-	443, 128, 388, 389, 383, 383, 383, 383, 
-	394, 383, 445, 132, 383, 446, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 132, 
-	383, 446, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 447, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 132, 383, 383, 
-	383, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 115, 116, 383, 383, 132, 429, 
-	383, 388, 389, 383, 383, 383, 383, 394, 
-	383, 115, 383, 422, 423, 428, 428, 119, 
-	388, 389, 383, 383, 383, 383, 426, 383, 
-	422, 423, 424, 428, 119, 388, 389, 383, 
-	383, 383, 143, 426, 383, 420, 383, 448, 
-	383, 435, 435, 119, 388, 389, 383, 383, 
-	383, 383, 394, 383, 420, 383, 420, 383, 
-	383, 383, 383, 383, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 420, 383, 420, 
-	383, 383, 383, 383, 449, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 420, 383, 
-	420, 383, 448, 383, 383, 383, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 420, 
-	383, 420, 116, 383, 383, 132, 421, 383, 
-	388, 389, 383, 383, 383, 383, 394, 383, 
-	420, 383, 413, 414, 419, 419, 119, 388, 
-	389, 383, 383, 383, 383, 417, 383, 413, 
-	414, 415, 419, 119, 388, 389, 383, 383, 
-	383, 145, 417, 383, 411, 383, 450, 383, 
-	435, 435, 119, 388, 389, 383, 383, 383, 
-	383, 394, 383, 411, 383, 411, 383, 383, 
-	383, 383, 383, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 411, 383, 411, 383, 
-	383, 383, 383, 451, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 411, 383, 411, 
-	383, 450, 383, 383, 383, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 411, 383, 
-	411, 116, 383, 383, 132, 412, 383, 388, 
-	389, 383, 383, 383, 383, 394, 383, 411, 
-	383, 404, 405, 410, 410, 119, 388, 389, 
-	383, 383, 383, 383, 408, 383, 404, 405, 
-	406, 410, 119, 388, 389, 383, 383, 383, 
-	147, 408, 383, 402, 383, 452, 383, 435, 
-	435, 119, 388, 389, 383, 383, 383, 383, 
-	394, 383, 402, 383, 402, 383, 383, 383, 
-	383, 383, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 402, 383, 402, 383, 383, 
-	383, 383, 453, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 402, 383, 402, 383, 
-	452, 383, 383, 383, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 402, 383, 402, 
-	116, 383, 383, 132, 403, 383, 388, 389, 
-	383, 383, 383, 383, 394, 383, 402, 383, 
-	395, 396, 401, 401, 119, 388, 389, 383, 
-	383, 383, 383, 399, 383, 395, 396, 397, 
-	401, 119, 388, 389, 383, 383, 383, 149, 
-	399, 383, 392, 383, 454, 383, 435, 435, 
-	119, 388, 389, 383, 383, 383, 383, 394, 
-	383, 392, 383, 392, 383, 383, 383, 383, 
-	383, 383, 388, 389, 383, 383, 383, 383, 
-	394, 383, 392, 383, 392, 383, 383, 383, 
-	383, 455, 383, 388, 389, 383, 383, 383, 
-	383, 394, 383, 392, 383, 392, 383, 454, 
-	383, 383, 383, 383, 388, 389, 383, 383, 
-	383, 383, 394, 383, 392, 383, 392, 116, 
-	383, 383, 132, 393, 383, 388, 389, 383, 
-	383, 383, 383, 394, 383, 392, 383, 384, 
-	385, 387, 387, 119, 388, 389, 383, 383, 
-	383, 383, 390, 383, 153, 154, 382, 382, 
-	382, 382, 382, 382, 382, 382, 161, 161, 
-	382, 382, 382, 153, 382, 167, 456, 169, 
-	170, 5, 171, 172, 173, 166, 166, 37, 
-	174, 166, 166, 153, 166, 177, 154, 166, 
-	166, 18, 178, 166, 171, 172, 166, 161, 
-	161, 166, 179, 166, 177, 166, 0
+	114, 151, 150, 114, 113, 80, 80, 81, 
+	76, 76, 76, 76, 76, 152, 113, 76, 
+	111, 80, 80, 81, 0, 0, 0, 0, 
+	0, 153, 111, 0, 154, 154, 155, 0, 
+	6, 6, 155, 0, 156, 156, 157, 0, 
+	158, 158, 157, 0, 157, 0, 159, 159, 
+	160, 0, 161, 161, 160, 0, 160, 0, 
+	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
 };
 
 static const short _indic_syllable_machine_trans_targs[] = {
-	143, 168, 170, 171, 3, 174, 4, 6, 
-	177, 7, 9, 180, 10, 12, 183, 13, 
-	15, 16, 164, 18, 19, 182, 21, 22, 
-	179, 24, 25, 176, 185, 189, 193, 196, 
-	200, 203, 207, 210, 214, 217, 143, 243, 
-	245, 246, 39, 249, 40, 42, 252, 43, 
-	45, 255, 46, 48, 258, 49, 51, 52, 
-	239, 54, 55, 257, 57, 58, 254, 60, 
-	61, 251, 260, 263, 267, 270, 274, 277, 
-	281, 284, 288, 292, 143, 316, 318, 319, 
-	75, 322, 143, 76, 78, 325, 79, 81, 
-	328, 82, 84, 331, 85, 87, 88, 312, 
-	90, 91, 330, 93, 94, 327, 96, 97, 
-	324, 333, 336, 340, 343, 347, 350, 354, 
-	357, 361, 143, 391, 393, 394, 110, 397, 
-	111, 113, 400, 114, 116, 403, 117, 119, 
-	406, 120, 122, 123, 387, 125, 126, 405, 
-	128, 129, 402, 131, 132, 399, 408, 411, 
-	415, 418, 422, 425, 429, 432, 436, 439, 
-	143, 144, 219, 293, 295, 364, 366, 313, 
-	315, 367, 365, 363, 440, 441, 143, 145, 
-	147, 35, 218, 165, 167, 187, 216, 146, 
-	34, 148, 212, 0, 149, 151, 33, 211, 
-	209, 150, 32, 152, 205, 153, 155, 31, 
-	204, 202, 154, 30, 156, 198, 157, 159, 
-	29, 197, 195, 158, 28, 160, 191, 161, 
-	163, 27, 190, 188, 162, 26, 173, 166, 
-	143, 169, 1, 172, 2, 175, 5, 23, 
-	178, 8, 20, 181, 11, 17, 184, 14, 
-	186, 192, 194, 199, 201, 206, 208, 213, 
-	215, 143, 220, 222, 71, 290, 240, 242, 
-	291, 221, 70, 223, 286, 36, 224, 226, 
-	69, 285, 283, 225, 68, 227, 279, 228, 
-	230, 67, 278, 276, 229, 66, 231, 272, 
-	232, 234, 65, 271, 269, 233, 64, 235, 
-	265, 236, 238, 63, 264, 262, 237, 62, 
-	248, 241, 143, 244, 37, 247, 38, 250, 
-	41, 59, 253, 44, 56, 256, 47, 53, 
-	259, 50, 261, 266, 268, 273, 275, 280, 
-	282, 287, 289, 143, 294, 106, 296, 359, 
-	72, 297, 299, 105, 358, 356, 298, 104, 
-	300, 352, 301, 303, 103, 351, 349, 302, 
-	102, 304, 345, 305, 307, 101, 344, 342, 
-	306, 100, 308, 338, 309, 311, 99, 337, 
-	335, 310, 98, 321, 314, 143, 317, 73, 
-	320, 74, 323, 77, 95, 326, 80, 92, 
-	329, 83, 89, 332, 86, 334, 339, 341, 
-	346, 348, 353, 355, 360, 362, 143, 143, 
-	368, 370, 142, 141, 388, 390, 438, 369, 
-	371, 434, 107, 372, 374, 140, 433, 431, 
-	373, 139, 375, 427, 376, 378, 138, 426, 
-	424, 377, 137, 379, 420, 380, 382, 136, 
-	419, 417, 381, 135, 383, 413, 384, 386, 
-	134, 412, 410, 385, 133, 396, 389, 143, 
-	392, 108, 395, 109, 398, 112, 130, 401, 
-	115, 127, 404, 118, 124, 407, 121, 409, 
-	414, 416, 421, 423, 428, 430, 435, 437, 
-	442
+	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
 };
 
 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, 
@@ -903,54 +987,61 @@ static const char _indic_syllable_machin
 	2, 0, 0, 2, 0, 0, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 2, 6, 2, 6, 2, 6, 2, 
 	6, 2, 7, 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, 
-	10, 2, 2, 6, 2, 11, 11, 0, 
-	0, 2, 6, 2, 0, 2, 12, 2, 
-	2, 0, 2, 0, 0, 2, 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, 
-	13, 0, 0, 2, 0, 2, 0, 0, 
+	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, 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, 
+	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, 14, 2, 2, 0, 2, 0, 0, 
-	2, 2, 0, 2, 2, 0, 2, 2, 
+	2, 19, 20, 2, 2, 0, 0, 0, 
+	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, 0, 15, 0, 0, 2, 0, 2, 
+	2, 0, 21, 0, 0, 2, 0, 2, 
 	0, 0, 2, 0, 0, 2, 0, 0, 
 	2, 0, 2, 2, 2, 2, 2, 2, 
-	2, 2, 2, 16, 6, 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, 17, 0, 0, 
-	2, 0, 2, 0, 0, 2, 0, 0, 
-	2, 0, 0, 2, 0, 2, 2, 2, 
-	2, 2, 2, 2, 2, 2, 18, 19, 
-	2, 2, 0, 0, 0, 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, 0, 20, 
-	0, 0, 2, 0, 2, 0, 0, 2, 
-	0, 0, 2, 0, 0, 2, 0, 2, 
-	2, 2, 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
 };
 
 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, 
@@ -962,17 +1053,24 @@ 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, 8, 
+	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, 9, 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, 
@@ -1021,17 +1119,24 @@ 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, 9, 
+	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, 10, 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, 
@@ -1076,66 +1181,73 @@ static const short _indic_syllable_machi
 	39, 39, 39, 39, 39, 39, 39, 39, 
 	39, 39, 39, 39, 39, 39, 39, 39, 
 	39, 39, 39, 39, 39, 39, 39, 39, 
 	39, 39, 39, 39, 39, 39, 39, 39, 
 	77, 77, 77, 83, 83, 77, 77, 77, 
 	77, 77, 77, 77, 77, 77, 77, 77, 
 	77, 77, 77, 77, 77, 77, 77, 77, 
 	77, 77, 77, 77, 77, 77, 77, 77, 
-	77, 77, 77, 115, 115, 115, 115, 115, 
+	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, 0, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 167, 167, 167, 167, 167, 
-	167, 167, 167, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 242, 242, 242, 
-	242, 242, 242, 242, 242, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 316, 316, 316, 316, 
-	316, 316, 316, 316, 383, 316, 383, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384, 
-	384, 384, 384, 384, 384, 384, 384, 384,