bug 603879 - part 1 - updated harfbuzz code from upstream. r=jdaggett a=blocking2.0
authorJonathan Kew <jfkthame@gmail.com>
Sat, 20 Nov 2010 17:49:12 +0000
changeset 57946 af5a5452cda4fd6e83e9d797f484feb0e2429393
parent 57945 baa6cc2f72e48cbb22e88bd574f5ef643f926a9c
child 57947 566c74963913f3b8792e6a334505d476b14055a7
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersjdaggett, blocking2
bugs603879
milestone2.0b8pre
bug 603879 - part 1 - updated harfbuzz code from upstream. r=jdaggett a=blocking2.0
gfx/harfbuzz/NEWS
gfx/harfbuzz/README
gfx/harfbuzz/TODO
gfx/harfbuzz/autogen.sh
gfx/harfbuzz/configure.ac
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/Makefile.in
gfx/harfbuzz/src/check-header-guards.sh
gfx/harfbuzz/src/check-internal-symbols.sh
gfx/harfbuzz/src/check-libstdc++.sh
gfx/harfbuzz/src/gen-arabic-joining-table.py
gfx/harfbuzz/src/hb-blob-private.h
gfx/harfbuzz/src/hb-blob.c
gfx/harfbuzz/src/hb-blob.h
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-buffer.h
gfx/harfbuzz/src/hb-common.c
gfx/harfbuzz/src/hb-common.h
gfx/harfbuzz/src/hb-font-private.h
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-font.h
gfx/harfbuzz/src/hb-ft.c
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-ft.h
gfx/harfbuzz/src/hb-glib.c
gfx/harfbuzz/src/hb-glib.h
gfx/harfbuzz/src/hb-graphite.cc
gfx/harfbuzz/src/hb-graphite.h
gfx/harfbuzz/src/hb-icu.c
gfx/harfbuzz/src/hb-icu.h
gfx/harfbuzz/src/hb-language.c
gfx/harfbuzz/src/hb-language.h
gfx/harfbuzz/src/hb-object-private.h
gfx/harfbuzz/src/hb-open-file-private.hh
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-head-private.hh
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-private.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-layout.h
gfx/harfbuzz/src/hb-ot-map-private.hh
gfx/harfbuzz/src/hb-ot-map.cc
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.h
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-private.hh
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-ot-shape.h
gfx/harfbuzz/src/hb-ot-tag.c
gfx/harfbuzz/src/hb-ot-tag.h
gfx/harfbuzz/src/hb-ot.h
gfx/harfbuzz/src/hb-private.h
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shape.h
gfx/harfbuzz/src/hb-unicode-private.h
gfx/harfbuzz/src/hb-unicode.c
gfx/harfbuzz/src/hb-unicode.h
gfx/harfbuzz/src/hb.h
gfx/harfbuzz/src/main.cc
gfx/harfbuzz/src/test.c
deleted file mode 100644
--- a/gfx/harfbuzz/README
+++ b/gfx/harfbuzz/README
@@ -1,9 +1,9 @@
-This is HarfBuzz, an OpenType Layout engine.
+This is HarfBuzz, a text shaping library.
 
 Bug reports on these files should be sent to the HarfBuzz mailing list as
 listed on http://freedesktop.org/wiki/Software/harfbuzz
 
 For license information, see the file COPYING.
 
 Behdad Esfahbod
 May 24, 2009
--- a/gfx/harfbuzz/TODO
+++ b/gfx/harfbuzz/TODO
@@ -1,12 +1,23 @@
+- Rename get_table to reference_table
+
+- Avoid allocating blob objects internally for for_data() faces
+
+- head table access cleanup (div by zero now!)
+- cache various expensive scale computation
+
+- SFNT api?  get_num_faces?
+
+- GNOME Bug 612402 - (hb-arm) HarfBuzz compilation fix for arm
+
+- Make sure LangSys default feature is only applied once...
 
 - kern/GPOS interaction
 
 - Use size_t in sanitize?
-- Buffer error handling?
 - Better define HB_INTERNAL
 - Future-proof metrics struct
 
 hb-ot:
 - Rename hb_internal_glyph_info_t to hb_ot_glyph_info_t
 - Add query API for aalt-like features
 - HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH vs LookupType::... mess
--- a/gfx/harfbuzz/autogen.sh
+++ b/gfx/harfbuzz/autogen.sh
@@ -166,19 +166,16 @@ do_cmd() {
 do_cmd $LIBTOOLIZE $LIBTOOLIZE_FLAGS
 
 do_cmd $ACLOCAL $ACLOCAL_FLAGS
 
 do_cmd $AUTOHEADER
 
 touch ChangeLog
 
-# We don't call gtkdocize right now.  When we do, we should then modify
-# the generated gtk-doc.make and move it to build/Makefile.am.gtk-doc.
-# See that file for details.
 #do_cmd $GTKDOCIZE $GTKDOCIZE_FLAGS
 
 do_cmd $AUTOMAKE $AUTOMAKE_FLAGS
 
 do_cmd $AUTOCONF
 
 cd "$ORIGDIR" || exit 1
 
--- a/gfx/harfbuzz/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,23 +1,22 @@
 AC_PREREQ(2.59)
-AC_INIT(harfbuzz, 0.1, [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz])
+AC_INIT(harfbuzz, 0.2, [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz])
 AC_CONFIG_SRCDIR([harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([1.9.6 gnu dist-bzip2 no-dist-gzip -Wall no-define])
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
 AC_LIBTOOL_WIN32_DLL
 AC_PROG_LIBTOOL dnl ([1.4]) Don't remove!
 
 AC_PROG_CC
+AM_PROG_CC_C_O
 AC_PROG_CXX
 
-AC_C_FLEXIBLE_ARRAY_MEMBER
-
 AC_CHECK_FUNCS(mprotect sysconf getpagesize)
 AC_CHECK_HEADERS(unistd.h sys/mman.h)
 
 # Make sure we don't link to libstdc++
 if test "x$GCC" = "xyes"; then
 	CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
 fi
 
@@ -30,16 +29,22 @@ fi
 AM_CONDITIONAL(HAVE_GLIB, $have_glib)
 
 PKG_CHECK_MODULES(ICU, icu, have_icu=true, have_icu=false)
 if $have_icu; then
 	AC_DEFINE(HAVE_ICU, 1, [Have ICU library])
 fi
 AM_CONDITIONAL(HAVE_ICU, $have_icu)
 
+PKG_CHECK_MODULES(GRAPHITE, silgraphite, have_graphite=true, have_graphite=false)
+if $have_graphite; then
+    AC_DEFINE(HAVE_GRAPHITE, 1, [Have Graphite library])
+fi
+AM_CONDITIONAL(HAVE_GRAPHITE, $have_graphite)
+
 PKG_CHECK_MODULES(FREETYPE, freetype2, have_freetype=true, have_freetype=false)
 if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
 	_save_libs="$LIBS"
 	_save_cflags="$CFLAGS"
 	LIBS="$LIBS $FREETYPE_LIBS"
 	CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
 	AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -1,26 +1,28 @@
 # Process this file with automake to produce Makefile.in
 
 NULL =
+EXTRA_DIST = 
 
 # The following warning options are useful for debugging: -Wpadded -Wcast-align
 #AM_CXXFLAGS =
 
 lib_LTLIBRARIES = libharfbuzz.la
 
 HBCFLAGS =
 HBLIBS =
 HBSOURCES =  \
 	hb-blob.c \
 	hb-blob-private.h \
 	hb-buffer.cc \
 	hb-buffer-private.hh \
+	hb-common.c \
 	hb-font.cc \
-	hb-font-private.hh \
+	hb-font-private.h \
 	hb-object-private.h \
 	hb-open-file-private.hh \
 	hb-open-type-private.hh \
 	hb-language.c \
 	hb-ot-head-private.hh \
 	hb-private.h \
 	hb-shape.cc \
 	hb-unicode.c \
@@ -40,23 +42,29 @@ HBHEADERS = \
 HBSOURCES += \
 	hb-ot-layout.cc \
 	hb-ot-layout-common-private.hh \
 	hb-ot-layout-gdef-private.hh \
 	hb-ot-layout-gpos-private.hh \
 	hb-ot-layout-gsubgpos-private.hh \
 	hb-ot-layout-gsub-private.hh \
 	hb-ot-layout-private.hh \
+	hb-ot-map.cc \
+	hb-ot-map-private.hh \
 	hb-ot-shape.cc \
+	hb-ot-shape-complex-arabic.cc \
+	hb-ot-shape-complex-arabic-table.h \
+	hb-ot-shape-complex-private.hh \
 	hb-ot-shape-private.hh \
 	hb-ot-tag.c \
 	$(NULL)
 HBHEADERS += \
 	hb-ot.h \
 	hb-ot-layout.h \
+	hb-ot-shape.h \
 	hb-ot-tag.h \
 	$(NULL)
 
 if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
 HBSOURCES += \
 	hb-glib.c \
@@ -76,36 +84,64 @@ HBHEADERS += \
 	hb-icu.h \
 	$(NULL)
 endif
 
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
 HBSOURCES += \
-	hb-ft.cc \
+	hb-ft.c \
 	$(NULL)
 HBHEADERS += \
 	hb-ft.h \
 	$(NULL)
 endif
 
+if HAVE_GRAPHITE
+HBCFLAGS += $(GRAPHITE_CFLAGS)
+HBLIBS   += $(GRAPHITE_LIBS)
+HBSOURCES += \
+	hb-graphite.cc \
+	$(NULL)
+HBHEADERS += \
+	hb-graphite.h \
+	$(NULL)
+endif
+
 CXXLINK = $(LINK)
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
 libharfbuzz_la_LIBADD = $(HBLIBS)
 pkginclude_HEADERS = $(HBHEADERS)
 
-noinst_PROGRAMS = main
+
+GENERATORS = \
+	gen-arabic-joining-table.py \
+	$(NULL)
+
+EXTRA_DIST += $(GENERATORS)
+
+noinst_PROGRAMS = main test
 
 main_SOURCES = main.cc
 main_CPPFLAGS = $(HBCFLAGS)
 main_LDADD = libharfbuzz.la $(HBLIBS)
 
+test_SOURCES = test.c
+test_CPPFLAGS = $(HBCFLAGS)
+test_LDADD = libharfbuzz.la $(HBLIBS)
+
 TESTS = \
-	check-internal-symbols.sh
+	check-c-linkage-decls.sh \
+	check-header-guards.sh \
+	check-internal-symbols.sh \
+	$(NULL)
 
 if HAVE_ICU
 else
+if HAVE_GRAPHITE
+else
 TESTS += check-libstdc++.sh
 endif
+endif
 
 -include $(top_srcdir)/git.mk
--- a/gfx/harfbuzz/src/Makefile.in
+++ b/gfx/harfbuzz/src/Makefile.in
@@ -45,18 +45,20 @@ CSRCS =            \
   hb-language.c    \
   hb-ot-tag.c      \
   hb-unicode.c     \
   $(NULL)
 
 CPPSRCS	=          \
   hb-buffer.cc     \
   hb-font.cc       \
+  hb-ot-layout.cc  \
+  hb-ot-map.cc     \
+  hb-ot-shape-complex-arabic.cc \
   hb-ot-shape.cc   \
-  hb-ot-layout.cc  \
   hb-shape.cc      \
   $(NULL)
 
 EXPORTS_NAMESPACES = harfbuzz
 
 EXPORTS_harfbuzz = \
   hb.h             \
   hb-blob.h        \
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/check-header-guards.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+cd "$srcdir"
+
+for x in hb-*.h hb-*.hh ; do
+	tag=`echo "$x" | tr 'a-z.-' 'A-Z_'`
+	lines=`grep "\<$tag\>" "$x" | wc -l`
+	if test "x$lines" != x3; then
+		echo "Ouch, header file $x does not have correct preprocessor guards"
+		stat=1
+	fi
+done
+
+exit $stat
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/check-internal-symbols.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+if which nm 2>/dev/null >/dev/null; then
+	:
+else
+	echo "check-internal-symbols.sh: 'nm' not found; skipping test"
+	exit 0
+fi
+
+test -z "$srcdir" && srcdir=.
+test -z "$MAKE" && MAKE=make
+stat=0
+
+so=.libs/libharfbuzz.so
+if test -f "$so"; then
+	echo "Checking that we are exposing internal symbols"
+	if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
+		echo "Ouch, internal symbols exposed"
+		stat=1
+	fi
+else
+	echo "check-internal-symbols.sh: libharfbuzz.so not found; skipping test"
+fi
+
+exit $stat
--- a/gfx/harfbuzz/src/check-libstdc++.sh
+++ b/gfx/harfbuzz/src/check-libstdc++.sh
@@ -6,17 +6,16 @@ export LC_ALL
 if which ldd 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-libstdc++.sh: 'ldd' not found; skipping test"
 	exit 0
 fi
 
 test -z "$srcdir" && srcdir=.
-test -z "$MAKE" && MAKE=make
 stat=0
 
 so=.libs/libharfbuzz.so
 if test -f "$so"; then
 	echo "Checking that we are not linking to libstdc++"
 	if ldd $so | grep 'libstdc[+][+]'; then
 		echo "Ouch, linked to libstdc++"
 		stat=1
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/gen-arabic-joining-table.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+
+import sys
+
+header = sys.stdin.readline(), sys.stdin.readline()
+dic = dict()
+for line in sys.stdin:
+	if line[:1] != '0':
+		continue
+
+	fields = [x.strip() for x in line.split(';')]
+	u = int(fields[0], 16)
+
+	if u == 0x200C or u == 0x200D:
+		continue
+	if u < 0x0600:
+		raise Exception ("Ooops, unexpected unicode character: ", fields)
+	dic[u] = fields
+
+v = dic.keys()
+v.sort()
+min_u, max_u = v[0], v[-1]
+occupancy = len(v) * 100 / (max_u - min_u + 1)
+
+# Maintain at least 40% occupancy in the table */
+if occupancy < 40:
+	raise Exception ("Table too sparse, please investigate: ", occupancy)
+
+print "/* == Start of generated table == */"
+print "/*"
+print " * The following table is generated by running:"
+print " *"
+print " *   ./gen-arabic-joining-table.py < ArabicShaping.txt"
+print " *"
+print " * on the ArabicShaping.txt file with the header:"
+print " *"
+for line in header:
+	print " * %s" % (line.strip())
+print " */"
+
+print "#define JOINING_TABLE_FIRST	0x%04x" % min_u
+print "#define JOINING_TABLE_LAST	0x%04x" % max_u
+print "static const uint8_t joining_table[JOINING_TABLE_LAST-JOINING_TABLE_FIRST+2] ="
+print "{"
+
+for i in range(min_u, max_u + 1):
+	if i not in dic:
+		print "  JOINING_TYPE_X, /* %04X */" % i
+	else:
+		entry = dic[i]
+		if entry[3] in ["ALAPH", "DALATH RISH"]:
+			value = "JOINING_GROUP_" + entry[3].replace(' ', '_')
+		else:
+			value = "JOINING_TYPE_" + entry[2]
+		print "  %s, /* %s */" % (value, '; '.join(entry))
+print "  JOINING_TYPE_X  /* dummy */"
+print "};"
+print "/* == End of generated table == */"
--- a/gfx/harfbuzz/src/hb-blob-private.h
+++ b/gfx/harfbuzz/src/hb-blob-private.h
@@ -28,16 +28,17 @@
 #define HB_BLOB_PRIVATE_H
 
 #include "hb-private.h"
 
 #include "hb-blob.h"
 
 HB_BEGIN_DECLS
 
+
 struct _hb_blob_t {
   hb_reference_count_t ref_count;
 
   unsigned int length;
 
   hb_mutex_t lock;
   /* the rest are protected by lock */
 
@@ -47,11 +48,12 @@ struct _hb_blob_t {
   const char *data;
 
   hb_destroy_func_t destroy;
   void *user_data;
 };
 
 extern HB_INTERNAL hb_blob_t _hb_blob_nil;
 
+
 HB_END_DECLS
 
 #endif /* HB_BLOB_PRIVATE_H */
--- a/gfx/harfbuzz/src/hb-blob.c
+++ b/gfx/harfbuzz/src/hb-blob.c
@@ -30,23 +30,26 @@
 
 #ifdef HAVE_SYS_MMAN_H
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <sys/mman.h>
 #endif /* HAVE_SYS_MMAN_H */
 
-#ifndef HB_DEBUG_BLOB
-#define HB_DEBUG_BLOB HB_DEBUG+0
-#endif
-
 #include <stdio.h>
 #include <errno.h>
 
+HB_BEGIN_DECLS
+
+
+#ifndef HB_DEBUG_BLOB
+#define HB_DEBUG_BLOB (HB_DEBUG+0)
+#endif
+
 hb_blob_t _hb_blob_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
   0, /* length */
 
   HB_MUTEX_INIT, /* lock */
 
   0, /* lock_count */
@@ -174,38 +177,38 @@ hb_blob_get_length (hb_blob_t *blob)
 const char *
 hb_blob_lock (hb_blob_t *blob)
 {
   if (HB_OBJECT_IS_INERT (blob))
     return NULL;
 
   hb_mutex_lock (blob->lock);
 
-  if (HB_DEBUG_BLOB)
+  (void) (HB_DEBUG_BLOB &&
     fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	     blob->lock_count, blob->data);
+	     blob->lock_count, blob->data));
 
   blob->lock_count++;
 
   hb_mutex_unlock (blob->lock);
 
   return blob->data;
 }
 
 void
 hb_blob_unlock (hb_blob_t *blob)
 {
   if (HB_OBJECT_IS_INERT (blob))
     return;
 
   hb_mutex_lock (blob->lock);
 
-  if (HB_DEBUG_BLOB)
+  (void) (HB_DEBUG_BLOB &&
     fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	     blob->lock_count, blob->data);
+	     blob->lock_count, blob->data));
 
   assert (blob->lock_count > 0);
   blob->lock_count--;
 
   hb_mutex_unlock (blob->lock);
 }
 
 hb_bool_t
@@ -237,76 +240,76 @@ static hb_bool_t
   pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
   pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
 #elif defined(HAVE_GETPAGESIZE)
   pagesize = (uintptr_t) getpagesize ();
 #endif
 
   if ((uintptr_t) -1L == pagesize) {
-    if (HB_DEBUG_BLOB)
-      fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno));
+    (void) (HB_DEBUG_BLOB &&
+      fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno)));
     return FALSE;
   }
-  if (HB_DEBUG_BLOB)
-    fprintf (stderr, "%p %s: pagesize is %u\n", blob, __FUNCTION__, pagesize);
+  (void) (HB_DEBUG_BLOB &&
+    fprintf (stderr, "%p %s: pagesize is %lu\n", blob, __FUNCTION__, (unsigned long) pagesize));
 
   mask = ~(pagesize-1);
   addr = (const char *) (((uintptr_t) blob->data) & mask);
   length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
-  if (HB_DEBUG_BLOB)
-    fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%d bytes)\n",
+  (void) (HB_DEBUG_BLOB &&
+    fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%lu bytes)\n",
 	     blob, __FUNCTION__,
-	     addr, addr+length, length);
+	     addr, addr+length, (unsigned long) length));
   if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
-    if (HB_DEBUG_BLOB)
-      fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno));
+    (void) (HB_DEBUG_BLOB &&
+      fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno)));
     return FALSE;
   }
 
-  if (HB_DEBUG_BLOB)
-    fprintf (stderr, "%p %s: successfully made [%p..%p] (%d bytes) writable\n",
+  (void) (HB_DEBUG_BLOB &&
+    fprintf (stderr, "%p %s: successfully made [%p..%p] (%lu bytes) writable\n",
 	     blob, __FUNCTION__,
-	     addr, addr+length, length);
+	     addr, addr+length, (unsigned long) length));
   return TRUE;
 #else
   return FALSE;
 #endif
 }
 
 static void
-_try_writable_inplace_locked (hb_blob_t *blob)
+try_writable_inplace_locked (hb_blob_t *blob)
 {
-  if (HB_DEBUG_BLOB)
-    fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__);
+  (void) (HB_DEBUG_BLOB &&
+    fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__));
 
   if (_try_make_writable_inplace_unix_locked (blob)) {
-    if (HB_DEBUG_BLOB)
-      fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__);
+    (void) (HB_DEBUG_BLOB &&
+      fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__));
     blob->mode = HB_MEMORY_MODE_WRITABLE;
   } else {
-    if (HB_DEBUG_BLOB)
-      fprintf (stderr, "%p %s: making writable -> FAILED\n", blob, __FUNCTION__);
+    (void) (HB_DEBUG_BLOB &&
+      fprintf (stderr, "%p %s: making writable -> FAILED\n", blob, __FUNCTION__));
     /* Failed to make writable inplace, mark that */
     blob->mode = HB_MEMORY_MODE_READONLY;
   }
 }
 
 hb_bool_t
 hb_blob_try_writable_inplace (hb_blob_t *blob)
 {
   hb_memory_mode_t mode;
 
   if (HB_OBJECT_IS_INERT (blob))
     return FALSE;
 
   hb_mutex_lock (blob->lock);
 
   if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
-    _try_writable_inplace_locked (blob);
+    try_writable_inplace_locked (blob);
 
   mode = blob->mode;
 
   hb_mutex_unlock (blob->lock);
 
   return mode == HB_MEMORY_MODE_WRITABLE;
 }
 
@@ -316,41 +319,44 @@ hb_blob_try_writable (hb_blob_t *blob)
   hb_memory_mode_t mode;
 
   if (HB_OBJECT_IS_INERT (blob))
     return FALSE;
 
   hb_mutex_lock (blob->lock);
 
   if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
-    _try_writable_inplace_locked (blob);
+    try_writable_inplace_locked (blob);
 
   if (blob->mode == HB_MEMORY_MODE_READONLY)
   {
     char *new_data;
 
-    if (HB_DEBUG_BLOB)
+    (void) (HB_DEBUG_BLOB &&
       fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	       blob->lock_count, blob->data);
+	       blob->lock_count, blob->data));
 
     if (blob->lock_count)
       goto done;
 
     new_data = malloc (blob->length);
     if (new_data) {
-      if (HB_DEBUG_BLOB)
-	fprintf (stderr, "%p %s: dupped successfully -> %p\n", blob, __FUNCTION__, blob->data);
+      (void) (HB_DEBUG_BLOB &&
+	fprintf (stderr, "%p %s: dupped successfully -> %p\n", blob, __FUNCTION__, blob->data));
       memcpy (new_data, blob->data, blob->length);
       _hb_blob_destroy_user_data (blob);
       blob->mode = HB_MEMORY_MODE_WRITABLE;
       blob->data = new_data;
       blob->destroy = free;
       blob->user_data = new_data;
     }
   }
 
 done:
   mode = blob->mode;
 
   hb_mutex_unlock (blob->lock);
 
   return mode == HB_MEMORY_MODE_WRITABLE;
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-blob.h
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -26,16 +26,17 @@
 
 #ifndef HB_BLOB_H
 #define HB_BLOB_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
+
 typedef enum {
   HB_MEMORY_MODE_DUPLICATE,
   HB_MEMORY_MODE_READONLY,
   HB_MEMORY_MODE_WRITABLE,
   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
 } hb_memory_mode_t;
 
 typedef struct _hb_blob_t hb_blob_t;
@@ -77,11 +78,12 @@ hb_bool_t
 hb_blob_is_writable (hb_blob_t *blob);
 
 hb_bool_t
 hb_blob_try_writable_inplace (hb_blob_t *blob);
 
 hb_bool_t
 hb_blob_try_writable (hb_blob_t *blob);
 
+
 HB_END_DECLS
 
 #endif /* HB_BLOB_H */
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -20,154 +20,127 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
  */
 
-#ifndef HB_BUFFER_PRIVATE_H
-#define HB_BUFFER_PRIVATE_H
+#ifndef HB_BUFFER_PRIVATE_HH
+#define HB_BUFFER_PRIVATE_HH
 
 #include "hb-private.h"
 #include "hb-buffer.h"
 #include "hb-unicode-private.h"
 
 HB_BEGIN_DECLS
 
-#define HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
 
-
-typedef struct _hb_internal_glyph_info_t {
-  hb_codepoint_t codepoint;
-  hb_mask_t      mask;
-  uint32_t       cluster;
-  uint16_t       component;
-  uint16_t       lig_id;
-  uint32_t       gproperty;
-} hb_internal_glyph_info_t;
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
-typedef struct _hb_internal_glyph_position_t {
-  hb_position_t  x_advance;
-  hb_position_t  y_advance;
-  hb_position_t  x_offset;
-  hb_position_t  y_offset;
-  uint32_t       back : 16;		/* number of glyphs to go back
-					   for drawing current glyph */
-  int32_t        cursive_chain : 16;	/* character to which this connects,
-					   may be positive or negative */
-} hb_internal_glyph_position_t;
-
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_internal_glyph_info_t));
-ASSERT_STATIC (sizeof (hb_glyph_position_t) == sizeof (hb_internal_glyph_position_t));
-ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+typedef struct _hb_segment_properties_t {
+    hb_direction_t      direction;
+    hb_script_t         script;
+    hb_language_t       language;
+} hb_segment_properties_t;
 
 
 HB_INTERNAL void
 _hb_buffer_swap (hb_buffer_t *buffer);
 
 HB_INTERNAL void
 _hb_buffer_clear_output (hb_buffer_t *buffer);
 
 HB_INTERNAL void
-_hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
-			      unsigned int num_in,
-			      unsigned int num_out,
-			      const hb_codepoint_t *glyph_data,
-			      unsigned short component,
-			      unsigned short ligID);
+_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
+				unsigned int num_in,
+				unsigned int num_out,
+				const uint16_t *glyph_data_be);
 
 HB_INTERNAL void
-_hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
-				   unsigned int num_in,
-				   unsigned int num_out,
-				   const uint16_t *glyph_data_be,
-				   unsigned short component,
-				   unsigned short ligID);
-
-HB_INTERNAL void
-_hb_buffer_add_output_glyph (hb_buffer_t *buffer,
-			     hb_codepoint_t glyph_index,
-			     unsigned short component,
-			     unsigned short ligID);
+_hb_buffer_replace_glyph (hb_buffer_t *buffer,
+			  hb_codepoint_t glyph_index);
 
 HB_INTERNAL void
 _hb_buffer_next_glyph (hb_buffer_t *buffer);
 
 
 HB_INTERNAL void
-_hb_buffer_clear_masks (hb_buffer_t *buffer);
+_hb_buffer_reset_masks (hb_buffer_t *buffer,
+			hb_mask_t    mask);
+
+HB_INTERNAL void
+_hb_buffer_add_masks (hb_buffer_t *buffer,
+		      hb_mask_t    mask);
 
 HB_INTERNAL void
 _hb_buffer_set_masks (hb_buffer_t *buffer,
 		      hb_mask_t    value,
 		      hb_mask_t    mask,
 		      unsigned int cluster_start,
 		      unsigned int cluster_end);
 
 
 struct _hb_buffer_t {
   hb_reference_count_t ref_count;
 
   /* Information about how the text in the buffer should be treated */
-  hb_unicode_funcs_t *unicode;
-  hb_direction_t      direction;
-  hb_script_t         script;
-  hb_language_t       language;
+
+  hb_unicode_funcs_t *unicode; /* Unicode functions */
+  hb_segment_properties_t props; /* Script, language, direction */
 
   /* Buffer contents */
 
   unsigned int allocated; /* Length of allocated arrays */
 
   hb_bool_t have_output; /* Whether we have an output buffer going on */
   hb_bool_t have_positions; /* Whether we have positions */
   hb_bool_t in_error; /* Allocation failed */
 
   unsigned int i; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
   unsigned int out_len; /* Length of ->out array */
 
-  hb_internal_glyph_info_t     *info;
-  hb_internal_glyph_info_t     *out_info;
-  hb_internal_glyph_position_t *pos;
+  hb_glyph_info_t     *info;
+  hb_glyph_info_t     *out_info;
+  hb_glyph_position_t *pos;
 
   /* Other stuff */
 
-  unsigned int max_lig_id;
+  unsigned int serial;
 
 
   /* Methods */
-  inline unsigned int allocate_lig_id (void) { return max_lig_id++; }
+  inline unsigned int next_serial (void) { return serial++; }
   inline void swap (void) { _hb_buffer_swap (this); }
   inline void clear_output (void) { _hb_buffer_clear_output (this); }
   inline void next_glyph (void) { _hb_buffer_next_glyph (this); }
-  inline void add_output_glyphs (unsigned int num_in,
-				 unsigned int num_out,
-				 const hb_codepoint_t *glyph_data,
-				 unsigned short component,
-				 unsigned short ligID)
-  { _hb_buffer_add_output_glyphs (this, num_in, num_out, glyph_data, component, ligID); }
-  inline void add_output_glyphs_be16 (unsigned int num_in,
-				      unsigned int num_out,
-				      const uint16_t *glyph_data_be,
-				      unsigned short component,
-				      unsigned short ligID)
-  { _hb_buffer_add_output_glyphs_be16 (this, num_in, num_out, glyph_data_be, component, ligID); }
-  inline void add_output_glyph (hb_codepoint_t glyph_index,
-				unsigned short component = 0xFFFF,
-				unsigned short ligID = 0xFFFF)
-  { _hb_buffer_add_output_glyph (this, glyph_index, component, ligID); }
-  inline void replace_glyph (hb_codepoint_t glyph_index) { add_output_glyph (glyph_index); }
+  inline void replace_glyphs_be16 (unsigned int num_in,
+				   unsigned int num_out,
+				   const uint16_t *glyph_data_be)
+  { _hb_buffer_replace_glyphs_be16 (this, num_in, num_out, glyph_data_be); }
+  inline void replace_glyph (hb_codepoint_t glyph_index)
+  { _hb_buffer_replace_glyph (this, glyph_index); }
 
-  inline void clear_masks (void) { _hb_buffer_clear_masks (this); }
-  inline void set_masks (hb_mask_t    value,
+  inline void reset_masks (hb_mask_t mask)
+  {
+    for (unsigned int i = 0; i < len; i++)
+      info[i].mask = mask;
+  }
+  inline void add_masks (hb_mask_t mask)
+  {
+    for (unsigned int i = 0; i < len; i++)
+      info[i].mask |= mask;
+  }
+  inline void set_masks (hb_mask_t value,
 			 hb_mask_t mask,
 			 unsigned int cluster_start,
 			 unsigned int cluster_end)
   { _hb_buffer_set_masks (this, value, mask, cluster_start, cluster_end); }
 
 };
 
 
 HB_END_DECLS
 
-#endif /* HB_BUFFER_PRIVATE_H */
+#endif /* HB_BUFFER_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -24,16 +24,18 @@
  *
  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
  */
 
 #include "hb-buffer-private.hh"
 
 #include <string.h>
 
+HB_BEGIN_DECLS
+
 
 static hb_buffer_t _hb_buffer_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
   &_hb_unicode_funcs_nil  /* unicode */
 };
 
 /* Here is how the buffer works internally:
@@ -57,60 +59,60 @@ static hb_buffer_t _hb_buffer_nil = {
 
 static hb_bool_t
 _hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
 {
   if (unlikely (buffer->in_error))
     return FALSE;
 
   unsigned int new_allocated = buffer->allocated;
-  hb_internal_glyph_position_t *new_pos;
-  hb_internal_glyph_info_t *new_info;
+  hb_glyph_position_t *new_pos;
+  hb_glyph_info_t *new_info;
   bool separate_out;
 
   separate_out = buffer->out_info != buffer->info;
 
   while (size > new_allocated)
     new_allocated += (new_allocated >> 1) + 8;
 
-  new_pos = (hb_internal_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
-  new_info = (hb_internal_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
+  new_pos = (hb_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
+  new_info = (hb_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
 
   if (unlikely (!new_pos || !new_info))
     buffer->in_error = TRUE;
 
   if (likely (new_pos))
     buffer->pos = new_pos;
 
   if (likely (new_info))
     buffer->info = new_info;
 
-  buffer->out_info = separate_out ? (hb_internal_glyph_info_t *) buffer->pos : buffer->info;
+  buffer->out_info = separate_out ? (hb_glyph_info_t *) buffer->pos : buffer->info;
   if (likely (!buffer->in_error))
     buffer->allocated = new_allocated;
 
   return likely (!buffer->in_error);
 }
 
 static inline hb_bool_t
 _hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
 {
   return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
 }
 
-static hb_bool_t
+static inline hb_bool_t
 _hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
 {
   if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE;
 
   if (buffer->out_info == buffer->info)
   {
     assert (buffer->have_output);
 
-    buffer->out_info = (hb_internal_glyph_info_t *) buffer->pos;
+    buffer->out_info = (hb_glyph_info_t *) buffer->pos;
     memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->out_info[0]));
   }
 
   return TRUE;
 }
 
 
 /* Public API */
@@ -175,102 +177,101 @@ hb_buffer_get_unicode_funcs (hb_buffer_t
   return buffer->unicode;
 }
 
 void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
 			 hb_direction_t  direction)
 
 {
-  buffer->direction = direction;
+  buffer->props.direction = direction;
 }
 
 hb_direction_t
 hb_buffer_get_direction (hb_buffer_t    *buffer)
 {
-  return buffer->direction;
+  return buffer->props.direction;
 }
 
 void
 hb_buffer_set_script (hb_buffer_t *buffer,
 		      hb_script_t  script)
 {
-  buffer->script = script;
+  buffer->props.script = script;
 }
 
 hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer)
 {
-  return buffer->script;
+  return buffer->props.script;
 }
 
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
 			hb_language_t  language)
 {
-  buffer->language = language;
+  buffer->props.language = language;
 }
 
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
 {
-  return buffer->language;
+  return buffer->props.language;
 }
 
 
 void
 hb_buffer_clear (hb_buffer_t *buffer)
 {
   buffer->have_output = FALSE;
   buffer->have_positions = FALSE;
   buffer->in_error = FALSE;
   buffer->len = 0;
   buffer->out_len = 0;
   buffer->i = 0;
   buffer->out_info = buffer->info;
-  buffer->max_lig_id = 0;
+  buffer->serial = 0;
 }
 
 hb_bool_t
 hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
 {
   return _hb_buffer_ensure (buffer, size);
 }
 
 void
 hb_buffer_add_glyph (hb_buffer_t    *buffer,
 		     hb_codepoint_t  codepoint,
 		     hb_mask_t       mask,
 		     unsigned int    cluster)
 {
-  hb_internal_glyph_info_t *glyph;
+  hb_glyph_info_t *glyph;
 
   if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
 
   glyph = &buffer->info[buffer->len];
+
+  memset (glyph, 0, sizeof (*glyph));
   glyph->codepoint = codepoint;
   glyph->mask = mask;
   glyph->cluster = cluster;
-  glyph->component = 0;
-  glyph->lig_id = 0;
-  glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
 
   buffer->len++;
 }
 
 void
 hb_buffer_clear_positions (hb_buffer_t *buffer)
 {
   _hb_buffer_clear_output (buffer);
   buffer->have_output = FALSE;
   buffer->have_positions = TRUE;
 
   if (unlikely (!buffer->pos))
   {
-    buffer->pos = (hb_internal_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
+    buffer->pos = (hb_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
     return;
   }
 
   memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
 }
 
 /* HarfBuzz-Internal API */
 
@@ -289,155 +290,72 @@ void
   unsigned int tmp;
 
   assert (buffer->have_output);
 
   if (unlikely (buffer->in_error)) return;
 
   if (buffer->out_info != buffer->info)
   {
-    hb_internal_glyph_info_t *tmp_string;
+    hb_glyph_info_t *tmp_string;
     tmp_string = buffer->info;
     buffer->info = buffer->out_info;
     buffer->out_info = tmp_string;
-    buffer->pos = (hb_internal_glyph_position_t *) buffer->out_info;
+    buffer->pos = (hb_glyph_position_t *) buffer->out_info;
   }
 
   tmp = buffer->len;
   buffer->len = buffer->out_len;
   buffer->out_len = tmp;
 
   buffer->i = 0;
 }
 
-/* The following function copies `num_out' elements from `glyph_data'
-   to `buffer->out_info', advancing the in array pointer in the structure
-   by `num_in' elements, and the out array pointer by `num_out' elements.
-   Finally, it sets the `length' field of `out' equal to
-   `pos' of the `out' structure.
-
-   If `component' is 0xFFFF, the component value from buffer->i
-   will copied `num_out' times, otherwise `component' itself will
-   be used to fill the `component' fields.
-
-   If `lig_id' is 0xFFFF, the lig_id value from buffer->i
-   will copied `num_out' times, otherwise `lig_id' itself will
-   be used to fill the `lig_id' fields.
-
-   The mask for all replacement glyphs are taken
-   from the glyph at position `buffer->i'.
-
-   The cluster value for the glyph at position buffer->i is used
-   for all replacement glyphs */
-
 void
-_hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
-			      unsigned int num_in,
-			      unsigned int num_out,
-			      const hb_codepoint_t *glyph_data,
-			      unsigned short component,
-			      unsigned short lig_id)
+_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
+				unsigned int num_in,
+				unsigned int num_out,
+				const uint16_t *glyph_data_be)
 {
-  unsigned int i;
-  unsigned int mask;
-  unsigned int cluster;
-
   if (buffer->out_info != buffer->info ||
       buffer->out_len + num_out > buffer->i + num_in)
   {
     if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
       return;
   }
 
-  mask = buffer->info[buffer->i].mask;
-  cluster = buffer->info[buffer->i].cluster;
-  if (component == 0xFFFF)
-    component = buffer->info[buffer->i].component;
-  if (lig_id == 0xFFFF)
-    lig_id = buffer->info[buffer->i].lig_id;
+  hb_glyph_info_t orig_info = buffer->info[buffer->i];
 
-  for (i = 0; i < num_out; i++)
+  for (unsigned int i = 0; i < num_out; i++)
   {
-    hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
-    info->codepoint = glyph_data[i];
-    info->mask = mask;
-    info->cluster = cluster;
-    info->component = component;
-    info->lig_id = lig_id;
-    info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
+    hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
+    *info = orig_info;
+    info->codepoint = hb_be_uint16 (glyph_data_be[i]);
   }
 
   buffer->i  += num_in;
   buffer->out_len += num_out;
 }
 
 void
-_hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
-				   unsigned int num_in,
-				   unsigned int num_out,
-				   const uint16_t *glyph_data_be,
-				   unsigned short component,
-				   unsigned short lig_id)
+_hb_buffer_replace_glyph (hb_buffer_t *buffer,
+			  hb_codepoint_t glyph_index)
 {
-  unsigned int i;
-  unsigned int mask;
-  unsigned int cluster;
-
-  if (buffer->out_info != buffer->info ||
-      buffer->out_len + num_out > buffer->i + num_in)
-  {
-    if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
-      return;
-  }
-
-  mask = buffer->info[buffer->i].mask;
-  cluster = buffer->info[buffer->i].cluster;
-  if (component == 0xFFFF)
-    component = buffer->info[buffer->i].component;
-  if (lig_id == 0xFFFF)
-    lig_id = buffer->info[buffer->i].lig_id;
-
-  for (i = 0; i < num_out; i++)
-  {
-    hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
-    info->codepoint = hb_be_uint16 (glyph_data_be[i]);
-    info->mask = mask;
-    info->cluster = cluster;
-    info->component = component;
-    info->lig_id = lig_id;
-    info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
-  }
-
-  buffer->i  += num_in;
-  buffer->out_len += num_out;
-}
-
-void
-_hb_buffer_add_output_glyph (hb_buffer_t *buffer,
-			     hb_codepoint_t glyph_index,
-			     unsigned short component,
-			     unsigned short lig_id)
-{
-  hb_internal_glyph_info_t *info;
+  hb_glyph_info_t *info;
 
   if (buffer->out_info != buffer->info)
   {
     if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
   }
   else if (buffer->out_len != buffer->i)
     buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
 
   info = &buffer->out_info[buffer->out_len];
   info->codepoint = glyph_index;
-  if (component != 0xFFFF)
-    info->component = component;
-  if (lig_id != 0xFFFF)
-    info->lig_id = lig_id;
-  info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
 
   buffer->i++;
   buffer->out_len++;
 }
 
 void
 _hb_buffer_next_glyph (hb_buffer_t *buffer)
 {
@@ -453,39 +371,54 @@ void
 
     buffer->out_len++;
   }
 
   buffer->i++;
 }
 
 void
-_hb_buffer_clear_masks (hb_buffer_t *buffer)
+_hb_buffer_reset_masks (hb_buffer_t *buffer,
+			hb_mask_t    mask)
 {
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask = 1;
+    buffer->info[i].mask = mask;
+}
+
+void
+_hb_buffer_add_masks (hb_buffer_t *buffer,
+		      hb_mask_t    mask)
+{
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    buffer->info[i].mask |= mask;
 }
 
 void
 _hb_buffer_set_masks (hb_buffer_t *buffer,
 		      hb_mask_t    value,
 		      hb_mask_t    mask,
 		      unsigned int cluster_start,
 		      unsigned int cluster_end)
 {
   hb_mask_t not_mask = ~mask;
+  value &= mask;
+
+  if (!mask)
+    return;
 
   if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
     unsigned int count = buffer->len;
     for (unsigned int i = 0; i < count; i++)
       buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
     return;
   }
 
+  /* XXX can't bsearch since .cluster may not be sorted. */
   /* Binary search to find the start position and go from there. */
   unsigned int min = 0, max = buffer->len;
   while (min < max)
   {
     unsigned int mid = min + ((max - min) / 2);
     if (buffer->info[mid].cluster < cluster_start)
       min = mid + 1;
     else
@@ -526,26 +459,26 @@ hb_buffer_get_glyph_positions (hb_buffer
 static void
 reverse_range (hb_buffer_t *buffer,
 	       unsigned int start,
 	       unsigned int end)
 {
   unsigned int i, j;
 
   for (i = start, j = end - 1; i < j; i++, j--) {
-    hb_internal_glyph_info_t t;
+    hb_glyph_info_t t;
 
     t = buffer->info[i];
     buffer->info[i] = buffer->info[j];
     buffer->info[j] = t;
   }
 
   if (buffer->pos) {
     for (i = 0, j = end - 1; i < j; i++, j--) {
-      hb_internal_glyph_position_t t;
+      hb_glyph_position_t t;
 
       t = buffer->pos[i];
       buffer->pos[i] = buffer->pos[j];
       buffer->pos[j] = t;
     }
   }
 }
 
@@ -687,8 +620,11 @@ hb_buffer_add_utf32 (hb_buffer_t    *buf
 		     unsigned int    text_length HB_UNUSED,
 		     unsigned int    item_offset,
 		     unsigned int    item_length)
 {
 #define UTF_NEXT(S, E, U)	((U) = *(S), (S)+1)
   ADD_UTF (uint32_t);
 #undef UTF_NEXT
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -29,32 +29,33 @@
 #define HB_BUFFER_H
 
 #include "hb-common.h"
 #include "hb-unicode.h"
 #include "hb-language.h"
 
 HB_BEGIN_DECLS
 
+
 typedef struct _hb_buffer_t hb_buffer_t;
 
 typedef struct _hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
   uint32_t       cluster;
-  uint32_t       internal1;
-  uint32_t       internal2;
+  hb_var_int_t   var1;
+  hb_var_int_t   var2;
 } hb_glyph_info_t;
 
 typedef struct _hb_glyph_position_t {
   hb_position_t  x_advance;
   hb_position_t  y_advance;
   hb_position_t  x_offset;
   hb_position_t  y_offset;
-  uint32_t       internal;
+  hb_var_int_t   var;
 } hb_glyph_position_t;
 
 
 hb_buffer_t *
 hb_buffer_create (unsigned int pre_alloc_size);
 
 hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer);
--- a/gfx/harfbuzz/src/hb-common.c
+++ b/gfx/harfbuzz/src/hb-common.c
@@ -21,21 +21,27 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.h"
 
+HB_BEGIN_DECLS
+
+
 hb_tag_t
 hb_tag_from_string (const char *s)
 {
   char tag[4];
   unsigned int i;
 
   for (i = 0; i < 4 && s[i]; i++)
     tag[i] = s[i];
   for (; i < 4; i++)
     tag[i] = ' ';
 
   return HB_TAG_STR (tag);
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -22,16 +22,27 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_COMMON_H
 #define HB_COMMON_H
 
+# ifdef __cplusplus
+#  define HB_BEGIN_DECLS	extern "C" {
+#  define HB_END_DECLS		}
+# else /* !__cplusplus */
+#  define HB_BEGIN_DECLS
+#  define HB_END_DECLS
+# endif /* !__cplusplus */
+
+HB_BEGIN_DECLS
+
+
 #ifdef _MSC_VER
 #define _HB__STR2__(x) #x
 #define _HB__STR1__(x) _HB__STR2__(x)
 #define _HB__LOC__ __FILE__ "("_HB__STR1__(__LINE__)") : Warning Msg: "
 #pragma message(_HB__LOC__"Not using stdint.h; integer types may have wrong size")
 typedef signed char int8_t;
 typedef unsigned char uint8_t;
 typedef signed short int16_t;
@@ -42,24 +53,16 @@ typedef signed long long int64_t;
 typedef unsigned long long uint64_t;
 #ifndef __cplusplus
 #define inline __inline
 #endif
 #else
 #include <stdint.h>
 #endif
 
-# ifdef __cplusplus
-#  define HB_BEGIN_DECLS	extern "C" {
-#  define HB_END_DECLS		}
-# else /* !__cplusplus */
-#  define HB_BEGIN_DECLS
-#  define HB_END_DECLS
-# endif /* !__cplusplus */
-
 typedef int hb_bool_t;
 
 typedef uint32_t hb_tag_t;
 #define HB_TAG(a,b,c,d) ((hb_tag_t)(((uint8_t)a<<24)|((uint8_t)b<<16)|((uint8_t)c<<8)|(uint8_t)d))
 #define HB_TAG_STR(s)   (HB_TAG(((const char *) s)[0], \
 				((const char *) s)[1], \
 				((const char *) s)[2], \
 				((const char *) s)[3]))
@@ -83,9 +86,21 @@ typedef enum _hb_direction_t {
 
 #define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 0)
 #define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 2)
 #define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 0)
 #define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 1)
 #define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1))
 
 
+typedef union _hb_var_int_t {
+  uint32_t u32;
+  int32_t i32;
+  uint16_t u16[2];
+  int16_t i16[2];
+  uint8_t u8[4];
+  int8_t i8[4];
+} hb_var_int_t;
+
+
+HB_END_DECLS
+
 #endif /* HB_COMMON_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-font-private.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_FONT_PRIVATE_H
+#define HB_FONT_PRIVATE_H
+
+#include "hb-private.h"
+
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+struct _hb_font_funcs_t {
+  hb_reference_count_t ref_count;
+
+  hb_bool_t immutable;
+
+  struct {
+    hb_font_get_glyph_func_t		get_glyph;
+    hb_font_get_glyph_advance_func_t	get_glyph_advance;
+    hb_font_get_glyph_extents_func_t	get_glyph_extents;
+    hb_font_get_contour_point_func_t	get_contour_point;
+    hb_font_get_kerning_func_t		get_kerning;
+  } v;
+};
+
+extern HB_INTERNAL hb_font_funcs_t _hb_font_funcs_nil;
+
+
+/*
+ * hb_face_t
+ */
+
+struct _hb_face_t {
+  hb_reference_count_t ref_count;
+
+  hb_get_table_func_t  get_table;
+  hb_destroy_func_t    destroy;
+  void                *user_data;
+
+  hb_blob_t *head_blob;
+  const struct head *head_table;
+
+  struct hb_ot_layout_t *ot_layout;
+};
+
+
+/*
+ * hb_font_t
+ */
+
+struct _hb_font_t {
+  hb_reference_count_t ref_count;
+
+  unsigned int x_scale;
+  unsigned int y_scale;
+
+  unsigned int x_ppem;
+  unsigned int y_ppem;
+
+  hb_font_funcs_t   *klass;
+  hb_destroy_func_t  destroy;
+  void              *user_data;
+};
+
+
+HB_END_DECLS
+
+#endif /* HB_FONT_PRIVATE_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_FONT_PRIVATE_H
-#define HB_FONT_PRIVATE_H
-
-#include "hb-private.h"
-
-#include "hb-font.h"
-
-#include "hb-ot-head-private.hh"
-
-HB_BEGIN_DECLS
-
-/*
- * hb_font_funcs_t
- */
-
-struct _hb_font_funcs_t {
-  hb_reference_count_t ref_count;
-
-  hb_bool_t immutable;
-
-  struct {
-    hb_font_get_glyph_func_t		get_glyph;
-    hb_font_get_contour_point_func_t	get_contour_point;
-    hb_font_get_glyph_metrics_func_t	get_glyph_metrics;
-    hb_font_get_kerning_func_t		get_kerning;
-  } v;
-};
-
-extern HB_INTERNAL hb_font_funcs_t _hb_font_funcs_nil;
-
-
-/*
- * hb_face_t
- */
-
-struct _hb_face_t {
-  hb_reference_count_t ref_count;
-
-  hb_get_table_func_t  get_table;
-  hb_destroy_func_t    destroy;
-  void                *user_data;
-
-  unsigned int         units_per_em;
-
-  struct hb_ot_layout_t *ot_layout;
-};
-
-
-/*
- * hb_font_t
- */
-
-struct _hb_font_t {
-  hb_reference_count_t ref_count;
-
-  unsigned int x_scale;
-  unsigned int y_scale;
-
-  unsigned int x_ppem;
-  unsigned int y_ppem;
-
-  hb_font_funcs_t   *klass;
-  hb_destroy_func_t  destroy;
-  void              *user_data;
-};
-
-
-HB_END_DECLS
-
-#endif /* HB_FONT_PRIVATE_H */
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -21,74 +21,82 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.h"
 
-#include "hb-font-private.hh"
+#include "hb-font-private.h"
 #include "hb-blob-private.h"
 #include "hb-open-file-private.hh"
 
 #include "hb-ot-layout-private.hh"
 
 #include <string.h>
 
+HB_BEGIN_DECLS
+
 
 /*
  * hb_font_funcs_t
  */
 
-HB_BEGIN_DECLS
-
 static hb_codepoint_t
 hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
 		       hb_face_t *face HB_UNUSED,
 		       const void *user_data HB_UNUSED,
 		       hb_codepoint_t unicode HB_UNUSED,
 		       hb_codepoint_t variation_selector HB_UNUSED)
 { return 0; }
 
+static void
+hb_font_get_glyph_advance_nil (hb_font_t *font HB_UNUSED,
+			       hb_face_t *face HB_UNUSED,
+			       const void *user_data HB_UNUSED,
+			       hb_codepoint_t glyph HB_UNUSED,
+			       hb_position_t *x_advance HB_UNUSED,
+			       hb_position_t *y_advance HB_UNUSED)
+{ }
+
+static void
+hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
+			       hb_face_t *face HB_UNUSED,
+			       const void *user_data HB_UNUSED,
+			       hb_codepoint_t glyph HB_UNUSED,
+			       hb_glyph_extents_t *extents HB_UNUSED)
+{ }
+
 static hb_bool_t
 hb_font_get_contour_point_nil (hb_font_t *font HB_UNUSED,
 			       hb_face_t *face HB_UNUSED,
 			       const void *user_data HB_UNUSED,
 			       unsigned int point_index HB_UNUSED,
 			       hb_codepoint_t glyph HB_UNUSED,
 			       hb_position_t *x HB_UNUSED,
 			       hb_position_t *y HB_UNUSED)
 { return false; }
 
-static void
-hb_font_get_glyph_metrics_nil (hb_font_t *font HB_UNUSED,
-			       hb_face_t *face HB_UNUSED,
-			       const void *user_data HB_UNUSED,
-			       hb_codepoint_t glyph HB_UNUSED,
-			       hb_glyph_metrics_t *metrics HB_UNUSED)
-{ }
-
 static hb_position_t
 hb_font_get_kerning_nil (hb_font_t *font HB_UNUSED,
 			 hb_face_t *face HB_UNUSED,
 			 const void *user_data HB_UNUSED,
 			 hb_codepoint_t first_glyph HB_UNUSED,
 			 hb_codepoint_t second_glyph HB_UNUSED)
 { return 0; }
 
-HB_END_DECLS
-
 hb_font_funcs_t _hb_font_funcs_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
   TRUE,  /* immutable */
   {
     hb_font_get_glyph_nil,
+    hb_font_get_glyph_advance_nil,
+    hb_font_get_glyph_extents_nil,
     hb_font_get_contour_point_nil,
-    hb_font_get_glyph_metrics_nil,
     hb_font_get_kerning_nil
   }
 };
 
 hb_font_funcs_t *
 hb_font_funcs_create (void)
 {
   hb_font_funcs_t *ffuncs;
@@ -138,86 +146,144 @@ void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
 {
   if (HB_OBJECT_IS_INERT (ffuncs))
     return;
 
   ffuncs->immutable = TRUE;
 }
 
+hb_bool_t
+hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->immutable;
+}
+
 
 void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t glyph_func)
 {
   if (ffuncs->immutable)
     return;
 
   ffuncs->v.get_glyph = glyph_func ? glyph_func : hb_font_get_glyph_nil;
 }
 
 void
+hb_font_funcs_set_glyph_advance_func (hb_font_funcs_t *ffuncs,
+				      hb_font_get_glyph_advance_func_t glyph_advance_func)
+{
+  if (ffuncs->immutable)
+    return;
+
+  ffuncs->v.get_glyph_advance = glyph_advance_func ? glyph_advance_func : hb_font_get_glyph_advance_nil;
+}
+
+void
+hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
+				      hb_font_get_glyph_extents_func_t glyph_extents_func)
+{
+  if (ffuncs->immutable)
+    return;
+
+  ffuncs->v.get_glyph_extents = glyph_extents_func ? glyph_extents_func : hb_font_get_glyph_extents_nil;
+}
+
+void
 hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
 				      hb_font_get_contour_point_func_t contour_point_func)
 {
   if (ffuncs->immutable)
     return;
 
   ffuncs->v.get_contour_point = contour_point_func ? contour_point_func : hb_font_get_contour_point_nil;
 }
 
 void
-hb_font_funcs_set_glyph_metrics_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_metrics_func_t glyph_metrics_func)
-{
-  if (ffuncs->immutable)
-    return;
-
-  ffuncs->v.get_glyph_metrics = glyph_metrics_func ? glyph_metrics_func : hb_font_get_glyph_metrics_nil;
-}
-
-void
 hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
 				hb_font_get_kerning_func_t kerning_func)
 {
   if (ffuncs->immutable)
     return;
 
   ffuncs->v.get_kerning = kerning_func ? kerning_func : hb_font_get_kerning_nil;
 }
 
 
+hb_font_get_glyph_func_t
+hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->v.get_glyph;
+}
+
+hb_font_get_glyph_advance_func_t
+hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->v.get_glyph_advance;
+}
+
+hb_font_get_glyph_extents_func_t
+hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->v.get_glyph_extents;
+}
+
+hb_font_get_contour_point_func_t
+hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->v.get_contour_point;
+}
+
+hb_font_get_kerning_func_t
+hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs)
+{
+  return ffuncs->v.get_kerning;
+}
+
+
+
 hb_codepoint_t
 hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector)
 {
   return font->klass->v.get_glyph (font, face, font->user_data,
 				   unicode, variation_selector);
 }
 
+void
+hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face,
+			   hb_codepoint_t glyph,
+			   hb_position_t *x_advance, hb_position_t *y_advance)
+{
+  *x_advance = *y_advance = 0;
+  return font->klass->v.get_glyph_advance (font, face, font->user_data,
+					   glyph, x_advance, y_advance);
+}
+
+void
+hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face,
+			   hb_codepoint_t glyph, hb_glyph_extents_t *extents)
+{
+  memset (extents, 0, sizeof (*extents));
+  return font->klass->v.get_glyph_extents (font, face, font->user_data,
+					   glyph, extents);
+}
+
 hb_bool_t
 hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
 			   unsigned int point_index,
 			   hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
 {
   *x = 0; *y = 0;
   return font->klass->v.get_contour_point (font, face, font->user_data,
 					   point_index,
 					   glyph, x, y);
 }
 
-void
-hb_font_get_glyph_metrics (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph, hb_glyph_metrics_t *metrics)
-{
-  memset (metrics, 0, sizeof (*metrics));
-  return font->klass->v.get_glyph_metrics (font, face, font->user_data,
-					   glyph, metrics);
-}
-
 hb_position_t
 hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
 		     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph)
 {
   return font->klass->v.get_kerning (font, face, font->user_data,
 				     first_glyph, second_glyph);
 }
 
@@ -228,53 +294,44 @@ hb_font_get_kerning (hb_font_t *font, hb
 
 static hb_face_t _hb_face_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
   NULL, /* get_table */
   NULL, /* destroy */
   NULL, /* user_data */
 
-  0,    /* units_per_em */
+  NULL, /* head_blob */
+  NULL, /* head_table */
 
   NULL  /* ot_layout */
 };
 
 
 hb_face_t *
 hb_face_create_for_tables (hb_get_table_func_t  get_table,
 			   hb_destroy_func_t    destroy,
 			   void                *user_data)
 {
   hb_face_t *face;
-  hb_blob_t *head_blob;
-  const struct head *head_table;
 
   if (!HB_OBJECT_DO_CREATE (hb_face_t, face)) {
     if (destroy)
       destroy (user_data);
     return &_hb_face_nil;
   }
 
   face->get_table = get_table;
   face->destroy = destroy;
   face->user_data = user_data;
 
   face->ot_layout = _hb_ot_layout_new (face);
 
-  head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
-  if (unlikely (hb_blob_get_length(head_blob) < head::min_size)) {
-    hb_face_destroy (face);
-    return &_hb_face_nil;
-  }
-
-  head_table = Sanitizer<head>::lock_instance (head_blob);
-  face->units_per_em = head_table->unitsPerEm;
-  hb_blob_unlock (head_blob);
-  hb_blob_destroy (head_blob);
+  face->head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
+  face->head_table = Sanitizer<head>::lock_instance (face->head_blob);
 
   return face;
 }
 
 
 typedef struct _hb_face_for_data_closure_t {
   hb_blob_t *blob;
   unsigned int  index;
@@ -284,17 +341,17 @@ static hb_face_for_data_closure_t *
 _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
 {
   hb_face_for_data_closure_t *closure;
 
   closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
     return NULL;
 
-  closure->blob = hb_blob_reference (blob);
+  closure->blob = blob;
   closure->index = index;
 
   return closure;
 }
 
 static void
 _hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
 {
@@ -318,19 +375,17 @@ static hb_blob_t *
 
   return blob;
 }
 
 hb_face_t *
 hb_face_create_for_data (hb_blob_t    *blob,
 			 unsigned int  index)
 {
-  hb_blob_reference (blob);
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (blob), index);
-  hb_blob_destroy (blob);
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
 
   if (unlikely (!closure))
     return &_hb_face_nil;
 
   return hb_face_create_for_tables (_hb_face_for_data_get_table,
 				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy,
 				    closure);
 }
@@ -350,16 +405,19 @@ hb_face_get_reference_count (hb_face_t *
 
 void
 hb_face_destroy (hb_face_t *face)
 {
   HB_OBJECT_DO_DESTROY (face);
 
   _hb_ot_layout_free (face->ot_layout);
 
+  hb_blob_unlock (face->head_blob);
+  hb_blob_destroy (face->head_blob);
+
   if (face->destroy)
     face->destroy (face->user_data);
 
   free (face);
 }
 
 hb_blob_t *
 hb_face_get_table (hb_face_t *face,
@@ -370,16 +428,22 @@ hb_face_get_table (hb_face_t *face,
   if (unlikely (!face || !face->get_table))
     return &_hb_blob_nil;
 
   blob = face->get_table (tag, face->user_data);
 
   return blob;
 }
 
+unsigned int
+hb_face_get_upem (hb_face_t *face)
+{
+  return (face->head_table ? face->head_table : &Null(head))->get_upem ();
+}
+
 
 /*
  * hb_font_t
  */
 
 static hb_font_t _hb_font_nil = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
 
@@ -449,31 +513,71 @@ hb_font_set_funcs (hb_font_t         *fo
   hb_font_funcs_reference (klass);
   hb_font_funcs_destroy (font->klass);
   font->klass = klass;
   font->destroy = destroy;
   font->user_data = user_data;
 }
 
 void
+hb_font_unset_funcs (hb_font_t          *font,
+		     hb_font_funcs_t   **klass,
+		     hb_destroy_func_t  *destroy,
+		     void              **user_data)
+{
+  /* None of the input arguments can be NULL. */
+
+  *klass = font->klass;
+  *destroy = font->destroy;
+  *user_data = font->user_data;
+
+  if (HB_OBJECT_IS_INERT (font))
+    return;
+
+  font->klass = NULL;
+  font->destroy = NULL;
+  font->user_data = NULL;
+}
+
+void
 hb_font_set_scale (hb_font_t *font,
 		   unsigned int x_scale,
 		   unsigned int y_scale)
 {
   if (HB_OBJECT_IS_INERT (font))
     return;
 
   font->x_scale = x_scale;
   font->y_scale = y_scale;
 }
 
 void
+hb_font_get_scale (hb_font_t *font,
+		   unsigned int *x_scale,
+		   unsigned int *y_scale)
+{
+  if (x_scale) *x_scale = font->x_scale;
+  if (y_scale) *y_scale = font->y_scale;
+}
+
+void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem)
 {
   if (HB_OBJECT_IS_INERT (font))
     return;
 
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
 }
 
+void
+hb_font_get_ppem (hb_font_t *font,
+		  unsigned int *x_ppem,
+		  unsigned int *y_ppem)
+{
+  if (x_ppem) *x_ppem = font->x_ppem;
+  if (y_ppem) *y_ppem = font->y_ppem;
+}
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -27,16 +27,17 @@
 #ifndef HB_FONT_H
 #define HB_FONT_H
 
 #include "hb-common.h"
 #include "hb-blob.h"
 
 HB_BEGIN_DECLS
 
+
 typedef struct _hb_face_t hb_face_t;
 typedef struct _hb_font_t hb_font_t;
 
 /*
  * hb_face_t
  */
 
 hb_face_t *
@@ -55,21 +56,36 @@ hb_face_t *
 hb_face_reference (hb_face_t *face);
 
 unsigned int
 hb_face_get_reference_count (hb_face_t *face);
 
 void
 hb_face_destroy (hb_face_t *face);
 
-/* Returns NULL if not found */
+/* XXX
+ *
+ * I have two major concerns about this API as it is right now:
+ *
+ *   - Jonathan Kew convinced me to make it return NULL if table not found (280af1bd),
+ *     however, that is WRONG IMO.  The API should not differentiate between a non-existing
+ *     table vs a zero-length table vs a very short table.  It only leads to implementations
+ *     that check for non-NULL and assume that they've got a usable table going on...  This
+ *     actually happened with Firefox.
+ *
+ *   - It has to be renamed to reference_table() since unlike any other _get_ API, a reference
+ *     ownership transfer happens and the user is responsible to destroy the result.
+ */
 hb_blob_t *
 hb_face_get_table (hb_face_t *face,
 		   hb_tag_t   tag);
 
+unsigned int
+hb_face_get_upem (hb_face_t *face);
+
 
 /*
  * hb_font_funcs_t
  */
 
 typedef struct _hb_font_funcs_t hb_font_funcs_t;
 
 hb_font_funcs_t *
@@ -85,69 +101,101 @@ void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
 
 hb_font_funcs_t *
 hb_font_funcs_copy (hb_font_funcs_t *ffuncs);
 
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
 
+hb_bool_t
+hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
 /* funcs */
 
-typedef struct _hb_glyph_metrics_t
+typedef struct _hb_glyph_extents_t
 {
-    hb_position_t x_advance;
-    hb_position_t y_advance;
-    hb_position_t x_offset;
-    hb_position_t y_offset;
+    hb_position_t x_bearing;
+    hb_position_t y_bearing;
     hb_position_t width;
     hb_position_t height;
-} hb_glyph_metrics_t;
+} hb_glyph_extents_t;
 
 typedef hb_codepoint_t (*hb_font_get_glyph_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
 						    hb_codepoint_t unicode, hb_codepoint_t variation_selector);
+typedef void (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+						  hb_codepoint_t glyph,
+						  hb_position_t *x_advance, hb_position_t *y_advance);
+typedef void (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+						  hb_codepoint_t glyph,
+						  hb_glyph_extents_t *metrics);
 typedef hb_bool_t (*hb_font_get_contour_point_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						       unsigned int point_index,
-						       hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y);
-typedef void (*hb_font_get_glyph_metrics_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						  hb_codepoint_t glyph, hb_glyph_metrics_t *metrics);
+						       unsigned int point_index, hb_codepoint_t glyph,
+						       hb_position_t *x, hb_position_t *y);
 typedef hb_position_t (*hb_font_get_kerning_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
 						     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
 
 
 void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t glyph_func);
 
 void
+hb_font_funcs_set_glyph_advance_func (hb_font_funcs_t *ffuncs,
+				      hb_font_get_glyph_advance_func_t glyph_advance_func);
+
+void
+hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
+				      hb_font_get_glyph_extents_func_t glyph_extents_func);
+
+void
 hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
 				      hb_font_get_contour_point_func_t contour_point_func);
 
 void
-hb_font_funcs_set_glyph_metrics_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_metrics_func_t glyph_metrics_func);
-
-void
 hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
 				hb_font_get_kerning_func_t kerning_func);
 
 
+/* These never return NULL.  Return fallback defaults instead. */
+
+hb_font_get_glyph_func_t
+hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs);
+
+hb_font_get_glyph_advance_func_t
+hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs);
+
+hb_font_get_glyph_extents_func_t
+hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs);
+
+hb_font_get_contour_point_func_t
+hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs);
+
+hb_font_get_kerning_func_t
+hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs);
+
+
 hb_codepoint_t
 hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector);
 
+void
+hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face,
+			   hb_codepoint_t glyph,
+			   hb_position_t *x_advance, hb_position_t *y_advance);
+
+void
+hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face,
+			   hb_codepoint_t glyph,
+			   hb_glyph_extents_t *metrics);
+
 hb_bool_t
 hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
-			   unsigned int point_index,
-			   hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y);
-
-void
-hb_font_get_glyph_metrics (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph, hb_glyph_metrics_t *metrics);
+			   unsigned int point_index, hb_codepoint_t glyph,
+			   hb_position_t *x, hb_position_t *y);
 
 hb_position_t
 hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
 		     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
 
 
 /*
  * hb_font_t
@@ -168,32 +216,55 @@ void
 hb_font_destroy (hb_font_t *font);
 
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
 		   hb_destroy_func_t  destroy,
 		   void              *user_data);
 
-hb_font_funcs_t *
-hb_font_get_funcs (hb_font_t       *font);
+/* Returns what was set and unsets it, but doesn't destroy(user_data).
+ * This is useful for wrapping / chaining font_funcs_t's.
+ *
+ * The client is responsible for:
+ *
+ *   - Take ownership of the reference on the returned klass,
+ *
+ *   - Calling "destroy(user_data)" exactly once if returned destroy func
+ *     is not NULL and the returned info is not needed anymore.
+ */
+void
+hb_font_unset_funcs (hb_font_t          *font,
+		     hb_font_funcs_t   **klass,
+		     hb_destroy_func_t  *destroy,
+		     void              **user_data);
 
 
 /*
  * We should add support for full matrices.
  */
 void
 hb_font_set_scale (hb_font_t *font,
 		   unsigned int x_scale,
 		   unsigned int y_scale);
 
+void
+hb_font_get_scale (hb_font_t *font,
+		   unsigned int *x_scale,
+		   unsigned int *y_scale);
+
 /*
  * A zero value means "no hinting in that direction"
  */
 void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem);
 
+void
+hb_font_get_ppem (hb_font_t *font,
+		  unsigned int *x_ppem,
+		  unsigned int *y_ppem);
+
 
 HB_END_DECLS
 
 #endif /* HB_FONT_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ft.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2009  Red Hat, Inc.
+ * Copyright (C) 2009  Keith Stribley <devel@thanlwinsoft.org>
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.h"
+
+#include "hb-ft.h"
+
+#include "hb-font-private.h"
+
+#include FT_TRUETYPE_TABLES_H
+
+HB_BEGIN_DECLS
+
+
+static hb_codepoint_t
+hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
+		 hb_face_t *face HB_UNUSED,
+		 const void *user_data,
+		 hb_codepoint_t unicode,
+		 hb_codepoint_t variation_selector)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+
+#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
+  if (unlikely (variation_selector)) {
+    hb_codepoint_t glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
+    if (glyph)
+      return glyph;
+  }
+#endif
+
+  return FT_Get_Char_Index (ft_face, unicode);
+}
+
+static void
+hb_ft_get_glyph_advance (hb_font_t *font HB_UNUSED,
+			 hb_face_t *face HB_UNUSED,
+			 const void *user_data,
+			 hb_codepoint_t glyph,
+			 hb_position_t *x_advance,
+			 hb_position_t *y_advance)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  /* TODO: load_flags, embolden, etc */
+
+  if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
+  {
+    *x_advance = ft_face->glyph->advance.x;
+    *y_advance = ft_face->glyph->advance.y;
+  }
+}
+
+static void
+hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
+			 hb_face_t *face HB_UNUSED,
+			 const void *user_data,
+			 hb_codepoint_t glyph,
+			 hb_glyph_extents_t *extents)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  /* TODO: load_flags, embolden, etc */
+
+  if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
+  {
+    /* XXX: A few negations should be in order here, not sure. */
+    extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
+    extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
+    extents->width = ft_face->glyph->metrics.width;
+    extents->height = ft_face->glyph->metrics.height;
+  }
+}
+
+static hb_bool_t
+hb_ft_get_contour_point (hb_font_t *font HB_UNUSED,
+			 hb_face_t *face HB_UNUSED,
+			 const void *user_data,
+			 unsigned int point_index,
+			 hb_codepoint_t glyph,
+			 hb_position_t *x,
+			 hb_position_t *y)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  /* TODO: load_flags, embolden, etc */
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+      return FALSE;
+
+  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
+      return FALSE;
+
+  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
+      return FALSE;
+
+  *x = ft_face->glyph->outline.points[point_index].x;
+  *y = ft_face->glyph->outline.points[point_index].y;
+
+  return TRUE;
+}
+
+static hb_position_t
+hb_ft_get_kerning (hb_font_t *font HB_UNUSED,
+		   hb_face_t *face HB_UNUSED,
+		   const void *user_data,
+		   hb_codepoint_t first_glyph,
+		   hb_codepoint_t second_glyph)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  FT_Vector kerning;
+
+  /* TODO: Kern type? */
+  if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning))
+      return 0;
+
+  return kerning.x;
+}
+
+static hb_font_funcs_t ft_ffuncs = {
+  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  TRUE, /* immutable */
+  {
+    hb_ft_get_glyph,
+    hb_ft_get_glyph_advance,
+    hb_ft_get_glyph_extents,
+    hb_ft_get_contour_point,
+    hb_ft_get_kerning
+  }
+};
+
+hb_font_funcs_t *
+hb_ft_get_font_funcs (void)
+{
+  return &ft_ffuncs;
+}
+
+
+static hb_blob_t *
+get_table  (hb_tag_t tag, void *user_data)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  FT_Byte *buffer;
+  FT_ULong  length = 0;
+  FT_Error error;
+
+  if (unlikely (tag == HB_TAG_NONE))
+    return NULL;
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+  if (error)
+    return NULL;
+
+  /* TODO Use FT_Memory? */
+  buffer = (FT_Byte *) malloc (length);
+  if (buffer == NULL)
+    return NULL;
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
+  if (error)
+    return NULL;
+
+  return hb_blob_create ((const char *) buffer, length,
+			 HB_MEMORY_MODE_WRITABLE,
+			 free, buffer);
+}
+
+
+hb_face_t *
+hb_ft_face_create (FT_Face           ft_face,
+		   hb_destroy_func_t destroy)
+{
+  hb_face_t *face;
+
+  if (ft_face->stream->read == NULL) {
+    hb_blob_t *blob;
+
+    blob = hb_blob_create ((const char *) ft_face->stream->base,
+			   (unsigned int) ft_face->stream->size,
+			   /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */
+			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+			   destroy, ft_face);
+    face = hb_face_create_for_data (blob, ft_face->face_index);
+    hb_blob_destroy (blob);
+  } else {
+    face = hb_face_create_for_tables (get_table, destroy, ft_face);
+  }
+
+  return face;
+}
+
+static void
+hb_ft_face_finalize (FT_Face ft_face)
+{
+  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
+}
+
+hb_face_t *
+hb_ft_face_create_cached (FT_Face ft_face)
+{
+  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+  {
+    if (ft_face->generic.finalizer)
+      ft_face->generic.finalizer (ft_face);
+
+    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
+    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+  }
+
+  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
+}
+
+
+hb_font_t *
+hb_ft_font_create (FT_Face           ft_face,
+		   hb_destroy_func_t destroy)
+{
+  hb_font_t *font;
+
+  font = hb_font_create ();
+  hb_font_set_funcs (font,
+		     hb_ft_get_font_funcs (),
+		     destroy, ft_face);
+  hb_font_set_scale (font,
+		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
+		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+  hb_font_set_ppem (font,
+		    ft_face->size->metrics.x_ppem,
+		    ft_face->size->metrics.y_ppem);
+
+  return font;
+}
+
+
+HB_END_DECLS
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright (C) 2009  Keith Stribley <devel@thanlwinsoft.org>
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-ft.h"
-
-#include "hb-font-private.hh"
-
-#include FT_TRUETYPE_TABLES_H
-
-static hb_codepoint_t
-hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
-		 hb_face_t *face HB_UNUSED,
-		 const void *user_data,
-		 hb_codepoint_t unicode,
-		 hb_codepoint_t variation_selector)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-
-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
-  if (unlikely (variation_selector)) {
-    hb_codepoint_t glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
-    if (glyph)
-      return glyph;
-  }
-#endif
-
-  return FT_Get_Char_Index (ft_face, unicode);
-}
-
-static hb_bool_t
-hb_ft_get_contour_point (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data,
-			 unsigned int point_index,
-			 hb_codepoint_t glyph,
-			 hb_position_t *x,
-			 hb_position_t *y)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  int load_flags = FT_LOAD_DEFAULT;
-
-  /* TODO: load_flags, embolden, etc */
-
-  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
-      return FALSE;
-
-  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
-      return FALSE;
-
-  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
-      return FALSE;
-
-  *x = ft_face->glyph->outline.points[point_index].x;
-  *y = ft_face->glyph->outline.points[point_index].y;
-
-  return TRUE;
-}
-
-static void
-hb_ft_get_glyph_metrics (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data,
-			 hb_codepoint_t glyph,
-			 hb_glyph_metrics_t *metrics)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  int load_flags = FT_LOAD_DEFAULT;
-
-  /* TODO: load_flags, embolden, etc */
-
-  metrics->x_advance = metrics->y_advance = 0;
-  metrics->x_offset = metrics->y_offset = 0;
-  metrics->width = metrics->height = 0;
-  if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
-  {
-    /* TODO: A few negations should be in order here, not sure. */
-    metrics->x_advance = ft_face->glyph->advance.x;
-    metrics->y_advance = ft_face->glyph->advance.y;
-    metrics->x_offset = ft_face->glyph->metrics.horiBearingX;
-    metrics->y_offset = ft_face->glyph->metrics.horiBearingY;
-    metrics->width = ft_face->glyph->metrics.width;
-    metrics->height = ft_face->glyph->metrics.height;
-  }
-}
-
-static hb_position_t
-hb_ft_get_kerning (hb_font_t *font HB_UNUSED,
-		   hb_face_t *face HB_UNUSED,
-		   const void *user_data,
-		   hb_codepoint_t first_glyph,
-		   hb_codepoint_t second_glyph)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  FT_Vector kerning;
-
-  /* TODO: Kern type? */
-  if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning))
-      return 0;
-
-  return kerning.x;
-}
-
-static hb_font_funcs_t ft_ffuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  TRUE, /* immutable */
-  {
-    hb_ft_get_glyph,
-    hb_ft_get_contour_point,
-    hb_ft_get_glyph_metrics,
-    hb_ft_get_kerning
-  }
-};
-
-hb_font_funcs_t *
-hb_ft_get_font_funcs (void)
-{
-  return &ft_ffuncs;
-}
-
-
-static hb_blob_t *
-_get_table  (hb_tag_t tag, void *user_data)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  FT_Byte *buffer;
-  FT_ULong  length = 0;
-  FT_Error error;
-
-  if (unlikely (tag == HB_TAG_NONE))
-    return NULL;
-
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
-  if (error)
-    return NULL;
-
-  /* TODO Use FT_Memory? */
-  buffer = (FT_Byte *) malloc (length);
-  if (buffer == NULL)
-    return NULL;
-
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
-  if (error)
-    return NULL;
-
-  return hb_blob_create ((const char *) buffer, length,
-			 HB_MEMORY_MODE_WRITABLE,
-			 free, buffer);
-}
-
-
-hb_face_t *
-hb_ft_face_create (FT_Face           ft_face,
-		   hb_destroy_func_t destroy)
-{
-  hb_face_t *face;
-
-  if (ft_face->stream->read == NULL) {
-    hb_blob_t *blob;
-
-    blob = hb_blob_create ((const char *) ft_face->stream->base,
-			   (unsigned int) ft_face->stream->size,
-			   /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */
-			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
-			   destroy, ft_face);
-    face = hb_face_create_for_data (blob, ft_face->face_index);
-    hb_blob_destroy (blob);
-  } else {
-    face = hb_face_create_for_tables (_get_table, destroy, ft_face);
-  }
-
-  return face;
-}
-
-static void
-hb_ft_face_finalize (FT_Face ft_face)
-{
-  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
-}
-
-hb_face_t *
-hb_ft_face_create_cached (FT_Face ft_face)
-{
-  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
-  {
-    if (ft_face->generic.finalizer)
-      ft_face->generic.finalizer (ft_face);
-
-    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
-    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
-  }
-
-  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
-}
-
-
-hb_font_t *
-hb_ft_font_create (FT_Face           ft_face,
-		   hb_destroy_func_t destroy)
-{
-  hb_font_t *font;
-
-  font = hb_font_create ();
-  hb_font_set_funcs (font,
-		     hb_ft_get_font_funcs (),
-		     destroy, ft_face);
-  hb_font_set_scale (font,
-		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
-		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
-  hb_font_set_ppem (font,
-		    ft_face->size->metrics.x_ppem,
-		    ft_face->size->metrics.y_ppem);
-
-  return font;
-}
--- a/gfx/harfbuzz/src/hb-ft.h
+++ b/gfx/harfbuzz/src/hb-ft.h
@@ -31,26 +31,28 @@
 
 #include "hb-font.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
 HB_BEGIN_DECLS
 
+
 hb_font_funcs_t *
 hb_ft_get_font_funcs (void);
 
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
 /* Note: This function is not thread-safe */
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face);
 
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
+
 HB_END_DECLS
 
 #endif /* HB_FT_H */
--- a/gfx/harfbuzz/src/hb-glib.c
+++ b/gfx/harfbuzz/src/hb-glib.c
@@ -27,16 +27,19 @@
 #include "hb-private.h"
 
 #include "hb-glib.h"
 
 #include "hb-unicode-private.h"
 
 #include <glib.h>
 
+HB_BEGIN_DECLS
+
+
 static hb_codepoint_t hb_glib_get_mirroring (hb_codepoint_t unicode) { g_unichar_get_mirror_char (unicode, &unicode); return unicode; }
 static hb_category_t hb_glib_get_general_category (hb_codepoint_t unicode) { return g_unichar_type (unicode); }
 static hb_script_t hb_glib_get_script (hb_codepoint_t unicode) { return g_unichar_get_script (unicode); }
 static unsigned int hb_glib_get_combining_class (hb_codepoint_t unicode) { return g_unichar_combining_class (unicode); }
 static unsigned int hb_glib_get_eastasian_width (hb_codepoint_t unicode) { return g_unichar_iswide (unicode); }
 
 
 static hb_unicode_funcs_t glib_ufuncs = {
@@ -51,8 +54,11 @@ static hb_unicode_funcs_t glib_ufuncs = 
   }
 };
 
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
   return &glib_ufuncs;
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-glib.h
+++ b/gfx/harfbuzz/src/hb-glib.h
@@ -26,14 +26,16 @@
 
 #ifndef HB_GLIB_H
 #define HB_GLIB_H
 
 #include "hb.h"
 
 HB_BEGIN_DECLS
 
+
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void);
 
+
 HB_END_DECLS
 
 #endif /* HB_GLIB_H */
--- a/gfx/harfbuzz/src/hb-graphite.cc
+++ b/gfx/harfbuzz/src/hb-graphite.cc
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2009, Martin Hosken
- * Copyright (C) 2009, SIL International
+ * Copyright (C) 2009  Martin Hosken
+ * Copyright (C) 2009  SIL International
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -24,20 +24,23 @@
  */
 
 #include <graphite/GrClient.h>
 #include <graphite/ITextSource.h>
 #include <graphite/GrData.h>
 #include <graphite/GrConstants.h>
 #include <graphite/Segment.h>
 #include "hb-buffer-private.hh"
-#include "hb-font-private.hh"
+#include "hb-font-private.h"
 #include "hb-graphite.h"
 #include <map>
 
+HB_BEGIN_DECLS
+
+
 namespace TtfUtil
 {
 extern int FontAscent(const void *pOS2);
 extern int FontDescent(const void *pOS2);
 extern int DesignUnits(const void *pHead);
 extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic);
 }
 
@@ -297,8 +300,11 @@ hb_graphite_shape (hb_font_t    *font,
     curradvy += pPosition->y_advance;
 //    fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
   }
 
   delete[] glyph_infos;
   delete[] firsts;
   delete[] flags;
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-graphite.h
+++ b/gfx/harfbuzz/src/hb-graphite.h
@@ -25,22 +25,23 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_GRAPHITE_H
 #define HB_GRAPHITE_H
 
 #include "hb-shape.h"
 
+HB_BEGIN_DECLS
 
-HB_BEGIN_DECLS
 
 #define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
 
 void hb_graphite_shape (hb_font_t    *font,
 			hb_face_t    *face,
 			hb_buffer_t  *buffer,
 			hb_feature_t *features,
 			unsigned int  num_features);
 
+
 HB_END_DECLS
 
 #endif /* HB_GRAPHITE_H */
--- a/gfx/harfbuzz/src/hb-icu.c
+++ b/gfx/harfbuzz/src/hb-icu.c
@@ -30,16 +30,19 @@
 #include "hb-icu.h"
 
 #include "hb-unicode-private.h"
 
 #include <unicode/uversion.h>
 #include <unicode/uchar.h>
 #include <unicode/uscript.h>
 
+HB_BEGIN_DECLS
+
+
 static hb_codepoint_t hb_icu_get_mirroring (hb_codepoint_t unicode) { return u_charMirror(unicode); }
 static unsigned int hb_icu_get_combining_class (hb_codepoint_t unicode) { return u_getCombiningClass (unicode); }
 
 static unsigned int
 hb_icu_get_eastasian_width (hb_codepoint_t unicode)
 {
   switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
   {
@@ -213,23 +216,29 @@ hb_icu_get_script (hb_codepoint_t unicod
   MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
   MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
   MATCH_SCRIPT (JAVANESE);               /* Java */
   MATCH_SCRIPT (KAITHI);                 /* Kthi */
   MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
 #if CHECK_ICU_VERSION (4, 4)
   MATCH_SCRIPT (LISU);                   /* Lisu */
 #endif
-  MATCH_SCRIPT (MEITEI_MAYEK);           /* Mtei */
+  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);/* Mtei */
 #if CHECK_ICU_VERSION (4, 4)
   MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
 #endif
   MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
   MATCH_SCRIPT (SAMARITAN);              /* Samr */
   MATCH_SCRIPT (TAI_VIET);               /* Tavt */
+
+  /* Unicode-6.0 additions */
+  MATCH_SCRIPT (BATAK);                  /* Batk */
+  MATCH_SCRIPT (BRAHMI);                 /* Brah */
+  MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
+
   }
   return HB_SCRIPT_UNKNOWN;
 }
 
 static hb_unicode_funcs_t icu_ufuncs = {
   HB_REFERENCE_COUNT_INVALID, /* ref_count */
   TRUE, /* immutable */
   {
@@ -241,8 +250,11 @@ static hb_unicode_funcs_t icu_ufuncs = {
   }
 };
 
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
   return &icu_ufuncs;
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-icu.h
+++ b/gfx/harfbuzz/src/hb-icu.h
@@ -26,14 +26,16 @@
 
 #ifndef HB_ICU_H
 #define HB_ICU_H
 
 #include "hb.h"
 
 HB_BEGIN_DECLS
 
+
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void);
 
+
 HB_END_DECLS
 
 #endif /* HB_ICU_H */
--- a/gfx/harfbuzz/src/hb-language.c
+++ b/gfx/harfbuzz/src/hb-language.c
@@ -23,16 +23,19 @@
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.h"
 
 #include "hb-language.h"
 
+HB_BEGIN_DECLS
+
+
 static const char canon_map[256] = {
    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
   '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
   '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
   'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
    0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
@@ -108,8 +111,10 @@ hb_language_from_string (const char *str
 }
 
 const char *
 hb_language_to_string (hb_language_t language)
 {
   return (const char *) language;
 }
 
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-language.h
+++ b/gfx/harfbuzz/src/hb-language.h
@@ -26,19 +26,21 @@
 
 #ifndef HB_LANGUAGE_H
 #define HB_LANGUAGE_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
+
 typedef const void *hb_language_t;
 
 hb_language_t
 hb_language_from_string (const char *str);
 
 const char *
 hb_language_to_string (hb_language_t language);
 
+
 HB_END_DECLS
 
 #endif /* HB_LANGUAGE_H */
--- a/gfx/harfbuzz/src/hb-object-private.h
+++ b/gfx/harfbuzz/src/hb-object-private.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2007 Chris Wilson
+ * Copyright (C) 2007  Chris Wilson
  * Copyright (C) 2009,2010  Red Hat, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
@@ -22,21 +22,22 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Contributor(s):
  *	Chris Wilson <chris@chris-wilson.co.uk>
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_REFCOUNT_PRIVATE_H
-#define HB_REFCOUNT_PRIVATE_H
+#ifndef HB_OBJECT_PRIVATE_H
+#define HB_OBJECT_PRIVATE_H
 
 #include "hb-private.h"
 
+HB_BEGIN_DECLS
 
 
 /* Encapsulate operations on the object's reference count */
 typedef struct {
   hb_atomic_int_t ref_count;
 } hb_reference_count_t;
 
 #define hb_reference_count_inc(RC) hb_atomic_int_fetch_and_add ((RC).ref_count, 1)
@@ -54,29 +55,29 @@ typedef struct {
 
 #define HB_REFERENCE_COUNT_HAS_REFERENCE(RC) (HB_REFERENCE_COUNT_GET_VALUE (RC) > 0)
 
 
 
 /* Debug */
 
 #ifndef HB_DEBUG_OBJECT
-#define HB_DEBUG_OBJECT HB_DEBUG+0
+#define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
 
 static inline void
 _hb_trace_object (const void *obj,
 		  hb_reference_count_t *ref_count,
 		  const char *function)
 {
-  if (HB_DEBUG_OBJECT)
-    fprintf (stderr, "OBJECT(%p) refcount=%d %s\n",
-	     obj,
-	     HB_REFERENCE_COUNT_GET_VALUE (*ref_count),
-	     function);
+  (void) (HB_DEBUG_OBJECT &&
+	  fprintf (stderr, "OBJECT(%p) refcount=%d %s\n",
+		   obj,
+		   HB_REFERENCE_COUNT_GET_VALUE (*ref_count),
+		   function));
 }
 
 #define TRACE_OBJECT(obj) _hb_trace_object (obj, &obj->ref_count, __FUNCTION__)
 
 
 
 /* Object allocation and lifecycle manamgement macros */
 
@@ -130,10 +131,11 @@ static inline void
     TRACE_OBJECT (obj); \
     old_count = hb_reference_count_dec (obj->ref_count); \
     assert (old_count > 0); \
     if (old_count != 1) \
       return; \
   } HB_STMT_END
 
 
+HB_END_DECLS
 
-#endif /* HB_REFCOUNT_PRIVATE_H */
+#endif /* HB_OBJECT_PRIVATE_H */
--- a/gfx/harfbuzz/src/hb-open-file-private.hh
+++ b/gfx/harfbuzz/src/hb-open-file-private.hh
@@ -24,16 +24,18 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OPEN_FILE_PRIVATE_HH
 #define HB_OPEN_FILE_PRIVATE_HH
 
 #include "hb-open-type-private.hh"
 
+HB_BEGIN_DECLS
+
 
 /*
  *
  * The OpenType Font File
  *
  */
 
 
@@ -72,17 +74,16 @@ typedef struct OffsetTable
   {
     if (unlikely (i >= numTables)) return Null(TableDirectory);
     return tableDir[i];
   }
   inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
   {
     Tag t;
     t.set (tag);
-    /* TODO: bsearch (need to sort in sanitize) */
     unsigned int count = numTables;
     for (unsigned int i = 0; i < count; i++)
     {
       if (t == tableDir[i].tag)
       {
         if (table_index) *table_index = i;
         return true;
       }
@@ -247,9 +248,11 @@ struct OpenTypeFontFile
   OpenTypeFontFace	fontFace;
   TTCHeader		ttcHeader;
   } u;
   public:
   DEFINE_SIZE_UNION (4, tag);
 };
 
 
+HB_END_DECLS
+
 #endif /* HB_OPEN_FILE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -19,23 +19,25 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OPEN_TYPES_PRIVATE_HH
-#define HB_OPEN_TYPES_PRIVATE_HH
+#ifndef HB_OPEN_TYPE_PRIVATE_HH
+#define HB_OPEN_TYPE_PRIVATE_HH
 
 #include "hb-private.h"
 
 #include "hb-blob.h"
 
+HB_BEGIN_DECLS
+HB_END_DECLS
 
 
 /*
  * Casts
  */
 
 /* Cast to struct T, reference to reference */
 template<typename Type, typename TObject>
@@ -119,44 +121,44 @@ inline Type& StructAfter(TObject &X)
  * Null objects
  */
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
 static const void *_NullPool[64 / sizeof (void *)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
-static inline const Type& Null () {
+static inline const Type& Null (void) {
   ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
   return *CastP<Type> (_NullPool);
 }
 
 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
 #define DEFINE_NULL_DATA(Type, data) \
 static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
 template <> \
-inline const Type& Null<Type> () { \
+inline const Type& Null<Type> (void) { \
   return *CastP<Type> (_Null##Type); \
 } /* The following line really exists such that we end in a place needing semicolon */ \
 ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 
 /* Accessor macro. */
 #define Null(Type) Null<Type>()
 
 
 /*
  * Trace
  */
 
 
 template <int max_depth>
 struct hb_trace_t {
   explicit hb_trace_t (unsigned int *pdepth, const char *what, const char *function, const void *obj) : pdepth(pdepth) {
-    if (*pdepth < max_depth)
-      fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function);
+    (void) (*pdepth < max_depth &&
+	    fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function));
     if (max_depth) ++*pdepth;
   }
   ~hb_trace_t (void) { if (max_depth) --*pdepth; }
 
   private:
   unsigned int *pdepth;
 };
 template <> /* Optimize when tracing is disabled */
@@ -166,17 +168,17 @@ struct hb_trace_t<0> {
 
 
 
 /*
  * Sanitize
  */
 
 #ifndef HB_DEBUG_SANITIZE
-#define HB_DEBUG_SANITIZE HB_DEBUG+0
+#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
 #endif
 
 
 #define TRACE_SANITIZE() \
 	hb_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", HB_FUNC, this); \
 
 
 struct hb_sanitize_context_t
@@ -185,86 +187,87 @@ struct hb_sanitize_context_t
   {
     this->blob = hb_blob_reference (blob);
     this->start = hb_blob_lock (blob);
     this->end = this->start + hb_blob_get_length (blob);
     this->writable = hb_blob_is_writable (blob);
     this->edit_count = 0;
     this->debug_depth = 0;
 
-    if (HB_DEBUG_SANITIZE)
-      fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
-	       this->blob, this->start, this->end, this->end - this->start);
+    (void) (HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "sanitize %p init [%p..%p] (%lu bytes)\n",
+	       this->blob, this->start, this->end,
+	       (unsigned long) (this->end - this->start)));
   }
 
   inline void finish (void)
   {
-    if (HB_DEBUG_SANITIZE)
+    (void) (HB_DEBUG_SANITIZE &&
       fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
-	       this->blob, this->start, this->end, this->edit_count);
+	       this->blob, this->start, this->end, this->edit_count));
 
     hb_blob_unlock (this->blob);
     hb_blob_destroy (this->blob);
     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;
     bool ret = this->start <= p &&
 	       p <= this->end &&
 	       (unsigned int) (this->end - p) >= len;
 
-    if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE) \
-      fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
+    (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n",
 	       p,
 	       this->debug_depth, this->debug_depth,
 	       p, p + len, len,
 	       this->start, this->end,
-	       ret ? "pass" : "FAIL");
+	       ret ? "pass" : "FAIL"));
 
     return likely (ret);
   }
 
   inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
   {
     const char *p = (const char *) base;
     bool overflows = record_size > 0 && len >= ((unsigned int) -1) / record_size;
 
-    if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
-      fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
+    (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n",
 	       p,
 	       this->debug_depth, this->debug_depth,
 	       p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
 	       this->start, this->end,
-	       !overflows ? "does not overflow" : "OVERFLOWS FAIL");
+	       !overflows ? "does not overflow" : "OVERFLOWS FAIL"));
 
     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 can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
   {
     const char *p = (const char *) base;
     this->edit_count++;
 
-    if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
-      fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
+    (void) (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n",
 	       p,
 	       this->debug_depth, this->debug_depth,
 	       this->edit_count,
 	       p, p + len, len,
 	       this->start, this->end,
-	       this->writable ? "granted" : "REJECTED");
+	       this->writable ? "granted" : "REJECTED"));
 
     return this->writable;
   }
 
   unsigned int debug_depth;
   const char *start, *end;
   bool writable;
   unsigned int edit_count;
@@ -282,59 +285,59 @@ struct Sanitizer
     bool sane;
 
     /* TODO is_sane() stuff */
 
     if (!blob)
       return hb_blob_create_empty ();
 
   retry:
-    if (HB_DEBUG_SANITIZE)
-      fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);
+    (void) (HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC));
 
     c->init (blob);
 
     if (unlikely (!c->start)) {
       c->finish ();
       return blob;
     }
 
     Type *t = CastP<Type> (const_cast<char *> (c->start));
 
     sane = t->sanitize (c);
     if (sane) {
       if (c->edit_count) {
-	if (HB_DEBUG_SANITIZE)
+	(void) (HB_DEBUG_SANITIZE &&
 	  fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n",
-		   blob, c->edit_count, HB_FUNC);
+		   blob, c->edit_count, HB_FUNC));
 
         /* sanitize again to ensure no toe-stepping */
         c->edit_count = 0;
 	sane = t->sanitize (c);
 	if (c->edit_count) {
-	  if (HB_DEBUG_SANITIZE)
+	  (void) (HB_DEBUG_SANITIZE &&
 	    fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
-		     blob, c->edit_count, HB_FUNC);
+		     blob, c->edit_count, HB_FUNC));
 	  sane = false;
 	}
       }
       c->finish ();
     } else {
       unsigned int edit_count = c->edit_count;
       c->finish ();
       if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
         /* ok, we made it writable by relocating.  try again */
-	if (HB_DEBUG_SANITIZE)
-	  fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC);
+	(void) (HB_DEBUG_SANITIZE &&
+	  fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC));
         goto retry;
       }
     }
 
-    if (HB_DEBUG_SANITIZE)
-      fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC);
+    (void) (HB_DEBUG_SANITIZE &&
+      fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC));
     if (sane)
       return blob;
     else {
       hb_blob_destroy (blob);
       return hb_blob_create_empty ();
     }
   }
 
@@ -364,41 +367,42 @@ struct Sanitizer
 template <typename Type, int Bytes> class BEInt;
 
 /* LONGTERMTODO: On machines allowing unaligned access, we can make the
  * following tighter by using byteswap instructions on ints directly. */
 template <typename Type>
 class BEInt<Type, 2>
 {
   public:
-  inline BEInt<Type,2>& set (Type i) { hb_be_uint16_put (v,i); return *this; }
-  inline operator Type () const { return hb_be_uint16_get (v); }
+  inline void set (Type i) { hb_be_uint16_put (v,i); }
+  inline operator Type (void) const { return hb_be_uint16_get (v); }
   inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); }
   inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
   private: uint8_t v[2];
 };
 template <typename Type>
 class BEInt<Type, 4>
 {
   public:
-  inline BEInt<Type,4>& set (Type i) { hb_be_uint32_put (v,i); return *this; }
-  inline operator Type () const { return hb_be_uint32_get (v); }
+  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_cmp (v, o.v); }
   inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
   private: uint8_t v[4];
 };
 
 /* Integer types in big-endian order and no alignment requirement */
 template <typename Type>
 struct IntType
 {
-  inline void set (Type i) { v.set(i); }
+  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; }
+  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 ();
     return likely (c->check_struct (this));
   }
   protected:
   BEInt<Type, sizeof (Type)> v;
   public:
   DEFINE_SIZE_STATIC (sizeof (Type));
@@ -562,34 +566,32 @@ struct GenericArrayOf
     return array + start_offset;
   }
 
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len)) return Null(Type);
     return array[i];
   }
-  inline unsigned int get_size () const
+  inline unsigned int get_size (void) const
   { return len.static_size + len * Type::static_size; }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (unlikely (!sanitize_shallow (c))) 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, hence the return.
+     * 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.
      */
-    return true;
-    /* We do keep this code though to make sure the structs pointed
-     * to do have a simple sanitize(), ie. they do not reference
-     * other structs. */
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      if (array[i].sanitize (c))
-        return false;
+    (void) (false && array[0].sanitize (c));
+
     return true;
   }
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
     TRACE_SANITIZE ();
     if (unlikely (!sanitize_shallow (c))) return false;
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!array[i].sanitize (c, base)))
@@ -668,43 +670,58 @@ struct OffsetListOf : OffsetArrayOf<Type
 template <typename Type>
 struct HeadlessArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= len || !i)) return Null(Type);
     return array[i-1];
   }
-  inline unsigned int get_size () const
+  inline unsigned int get_size (void) const
   { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
 
   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 ();
     if (unlikely (!sanitize_shallow (c))) 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, hence the return.
+     * 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.
      */
-    return true;
-    /* We do keep this code though to make sure the structs pointed
-     * to do have a simple sanitize(), ie. they do not reference
-     * other structs. */
-    unsigned int count = len ? len - 1 : 0;
-    Type *a = array;
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!a[i].sanitize (c)))
-        return false;
+    (void) (false && array[0].sanitize (c));
+
     return true;
   }
 
   USHORT len;
   Type array[VAR];
   public:
   DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
 };
 
 
+/* An array with sorted elements.  Supports binary searching. */
+template <typename Type>
+struct SortedArrayOf : ArrayOf<Type> {
+
+  template <typename SearchType>
+  inline int search (const SearchType &x) const {
+    class Cmp {
+      public: static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
+    };
+    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;
+  }
+};
+
+
+HB_BEGIN_DECLS
+HB_END_DECLS
+
 #endif /* HB_OPEN_TYPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-head-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-private.hh
@@ -24,34 +24,42 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_HEAD_PRIVATE_HH
 #define HB_OT_HEAD_PRIVATE_HH
 
 #include "hb-open-type-private.hh"
 
+HB_BEGIN_DECLS
+
+
 /*
  * head
  */
 
 #define HB_OT_TAG_head HB_TAG('h','e','a','d')
 
 struct head
 {
   static const hb_tag_t Tag	= HB_OT_TAG_head;
 
+  inline unsigned int get_upem (void) const {
+    unsigned int upem = unitsPerEm;
+    /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */
+    return 16 <= upem && upem <= 16384 ? upem : 1000;
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     /* Shall we check for magicNumber here?  Who cares? */
-    return c->check_struct (this) &&
-      likely (version.major == 1) &&
-      likely (unitsPerEm >= 16 && unitsPerEm <= 16384);
+    return c->check_struct (this) && likely (version.major == 1);
   }
 
+  private:
   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
 					 * entire font as ULONG, then store
 					 * 0xB1B0AFBA - sum. */
   ULONG		magicNumber;		/* Set to 0x5F0F3CF5. */
   USHORT	flags;			/* Bit 0: Baseline for font at y=0;
@@ -122,9 +130,11 @@ 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);
 };
 
 
+HB_END_DECLS
+
 #endif /* HB_OT_HEAD_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,63 +18,74 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
 
 #include "hb-ot-layout-private.hh"
 
 #include "hb-open-type-private.hh"
 
 
 #define NO_CONTEXT		((unsigned int) 0x110000)
 #define NOT_COVERED		((unsigned int) 0x110000)
 #define MAX_NESTING_LEVEL	8
 
+HB_BEGIN_DECLS
+HB_END_DECLS
+
 
 /*
  *
  * OpenType Layout Common Table Formats
  *
  */
 
 
 /*
  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
  */
 
 template <typename Type>
 struct Record
 {
+  inline int cmp (hb_tag_t a) const {
+    return tag.cmp (a);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
     TRACE_SANITIZE ();
     return c->check_struct (this)
 	&& offset.sanitize (c, base);
   }
 
   Tag		tag;		/* 4-byte Tag identifier */
   OffsetTo<Type>
 		offset;		/* Offset from beginning of object holding
 				 * the Record */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 template <typename Type>
-struct RecordArrayOf : ArrayOf<Record<Type> > {
+struct RecordArrayOf : SortedArrayOf<Record<Type> > {
   inline const Tag& get_tag (unsigned int i) const
   {
+    /* We cheat slightly and don't define separate Null objects
+     * for Record types.  Instead, we return the correct Null(Tag)
+     * here. */
     if (unlikely (i >= this->len)) return Null(Tag);
     return (*this)[i].tag;
   }
   inline unsigned int get_tags (unsigned int start_offset,
 				unsigned int *record_count /* IN/OUT */,
 				hb_tag_t     *record_tags /* OUT */) const
   {
     if (record_count) {
@@ -81,47 +93,61 @@ struct RecordArrayOf : ArrayOf<Record<Ty
       unsigned int count = *record_count;
       for (unsigned int i = 0; i < count; i++)
 	record_tags[i] = array[i].tag;
     }
     return this->len;
   }
   inline bool find_index (hb_tag_t tag, unsigned int *index) const
   {
-    Tag t;
-    t.set (tag);
-    /* TODO: bsearch (need to sort in sanitize) */
-    const Record<Type> *a = this->array;
-    unsigned int count = this->len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (t == a[i].tag)
-      {
+    int i = this->search (tag);
+    if (i != -1) {
         if (index) *index = i;
         return true;
-      }
+    } else {
+      if (index) *index = Index::NOT_FOUND_INDEX;
+      return false;
     }
-    if (index) *index = Index::NOT_FOUND_INDEX;
-    return false;
   }
 };
 
 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 ();
     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 ();
+    return c->check_struct (this);
+  }
+
+  GlyphID	start;		/* First GlyphID in the range */
+  GlyphID	end;		/* Last GlyphID in the range */
+  USHORT	value;		/* Value */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+DEFINE_NULL_DATA (RangeRecord, "\000\001");
+
+
 struct IndexArray : ArrayOf<Index>
 {
   inline unsigned int get_indexes (unsigned int start_offset,
 				   unsigned int *_count /* IN/OUT */,
 				   unsigned int *_indexes /* OUT */) const
   {
     if (_count) {
       const USHORT *array = this->sub_array (start_offset, _count);
@@ -229,18 +255,16 @@ struct Feature
   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return c->check_struct (this)
 	&& lookupIndex.sanitize (c);
   }
 
-  /* LONGTERMTODO: implement get_feature_parameters() */
-  /* LONGTERMTODO: implement FeatureSize and other special features? */
   Offset	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);
 };
@@ -264,17 +288,21 @@ struct LookupFlag : USHORT
   DEFINE_SIZE_STATIC (2);
 };
 
 struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
 
   inline unsigned int get_type (void) const { return lookupType; }
-  inline unsigned int get_flag (void) const
+
+  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
+   * higher 16-bit is mark-filtering-set if the lookup uses one.
+   * Not to be confused with glyph_props which is very similar. */
+  inline uint32_t get_props (void) const
   {
     unsigned int flag = lookupFlag;
     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
     {
       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       flag += (markFilteringSet << 16);
     }
     return flag;
@@ -313,95 +341,58 @@ typedef OffsetListOf<Lookup> LookupList;
 
 struct CoverageFormat1
 {
   friend struct Coverage;
 
   private:
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
-    if (unlikely (glyph_id > 0xFFFF))
-      return NOT_COVERED;
-    GlyphID gid;
-    gid.set (glyph_id);
-    /* TODO: bsearch (need to sort in sanitize) */
-    unsigned int num_glyphs = glyphArray.len;
-    for (unsigned int i = 0; i < num_glyphs; i++)
-      if (gid == glyphArray[i])
+    int i = glyphArray.search (glyph_id);
+    if (i != -1)
         return i;
     return NOT_COVERED;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return glyphArray.sanitize (c);
   }
 
   private:
   USHORT	coverageFormat;	/* Format identifier--format = 1 */
-  ArrayOf<GlyphID>
+  SortedArrayOf<GlyphID>
 		glyphArray;	/* Array of GlyphIDs--in numerical order */
   public:
   DEFINE_SIZE_ARRAY (4, glyphArray);
 };
 
-struct CoverageRangeRecord
-{
-  friend struct CoverageFormat2;
-
-  private:
-  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
-  {
-    if (glyph_id >= start && glyph_id <= end)
-      return (unsigned int) startCoverageIndex + (glyph_id - start);
-    return NOT_COVERED;
-  }
-
-  public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return c->check_struct (this);
-  }
-
-  private:
-  GlyphID	start;			/* First GlyphID in the range */
-  GlyphID	end;			/* Last GlyphID in the range */
-  USHORT	startCoverageIndex;	/* Coverage Index of first GlyphID in
-					 * range */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-DEFINE_NULL_DATA (CoverageRangeRecord, "\000\001");
-
 struct CoverageFormat2
 {
   friend struct Coverage;
 
   private:
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
-    /* TODO: bsearch (need to sort in sanitize) */
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      unsigned int coverage = rangeRecord[i].get_coverage (glyph_id);
-      if (coverage != NOT_COVERED)
-        return coverage;
+    int i = rangeRecord.search (glyph_id);
+    if (i != -1) {
+      const RangeRecord &range = rangeRecord[i];
+      return (unsigned int) range.value + (glyph_id - range.start);
     }
     return NOT_COVERED;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return rangeRecord.sanitize (c);
   }
 
   private:
   USHORT	coverageFormat;	/* Format identifier--format = 2 */
-  ArrayOf<CoverageRangeRecord>
+  SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID. rangeCount entries
 				 * long */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct Coverage
@@ -442,17 +433,17 @@ struct Coverage
  * Class Definition Table
  */
 
 struct ClassDefFormat1
 {
   friend struct ClassDef;
 
   private:
-  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
       return classValue[glyph_id - startGlyph];
     return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
@@ -463,79 +454,47 @@ struct ClassDefFormat1
   USHORT	classFormat;		/* Format identifier--format = 1 */
   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
   ArrayOf<USHORT>
 		classValue;		/* Array of Class Values--one per GlyphID */
   public:
   DEFINE_SIZE_ARRAY (6, classValue);
 };
 
-struct ClassRangeRecord
-{
-  friend struct ClassDefFormat2;
-
-  private:
-  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
-  {
-    if (glyph_id >= start && glyph_id <= end)
-      return classValue;
-    return 0;
-  }
-
-  public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return c->check_struct (this);
-  }
-
-  private:
-  GlyphID	start;		/* First GlyphID in the range */
-  GlyphID	end;		/* Last GlyphID in the range */
-  USHORT	classValue;	/* Applied to all glyphs in the range */
-  public:
-  DEFINE_SIZE_STATIC (6);
-};
-DEFINE_NULL_DATA (ClassRangeRecord, "\000\001");
-
 struct ClassDefFormat2
 {
   friend struct ClassDef;
 
   private:
-  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+  inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
-    /* TODO: bsearch (need to sort in sanitize) */
-    unsigned int count = rangeRecord.len;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      int classValue = rangeRecord[i].get_class (glyph_id);
-      if (classValue > 0)
-        return classValue;
-    }
+    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 ();
     return rangeRecord.sanitize (c);
   }
 
   USHORT	classFormat;	/* Format identifier--format = 2 */
-  ArrayOf<ClassRangeRecord>
+  SortedArrayOf<RangeRecord>
 		rangeRecord;	/* Array of glyph ranges--ordered by
 				 * Start GlyphID */
   public:
   DEFINE_SIZE_ARRAY (4, rangeRecord);
 };
 
 struct ClassDef
 {
-  inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
+  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
 
-  inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+  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;
     }
   }
 
@@ -561,25 +520,40 @@ struct ClassDef
 
 
 /*
  * Device Tables
  */
 
 struct Device
 {
-  /* XXX speed up */
 
   inline hb_position_t get_x_delta (hb_ot_layout_context_t *c) const
-  { return c->font->x_ppem ? get_delta (c->font->x_ppem) * (uint64_t) c->font->x_scale / c->font->x_ppem : 0; }
+  { return get_delta (c->font->x_ppem, c->font->x_scale); }
 
   inline hb_position_t get_y_delta (hb_ot_layout_context_t *c) const
-  { return c->font->y_ppem ? get_delta (c->font->y_ppem) * (uint64_t) c->font->y_scale / c->font->y_ppem : 0; }
+  { return get_delta (c->font->y_ppem, c->font->y_scale); }
+
+  inline int get_delta (unsigned int ppem, unsigned int scale) const
+  {
+    if (!ppem) return 0;
+
+    int pixels = get_delta_pixels (ppem);
+
+    if (!pixels) return 0;
 
-  inline int get_delta (unsigned int ppem_size) const
+    /* pixels is at most in the -8..7 range.  So 64-bit arithmetic is
+     * not really necessary here.  A simple cast to int may just work
+     * as well.  But since this code is not reached that often and
+     * for the sake of correctness, we do a 64bit operation. */
+    return pixels * (int64_t) scale / ppem;
+  }
+
+
+  inline int get_delta_pixels (unsigned int ppem_size) const
   {
     unsigned int f = deltaFormat;
     if (unlikely (f < 1 || f > 3))
       return 0;
 
     if (ppem_size < startSize || ppem_size > endSize)
       return 0;
 
@@ -592,17 +566,17 @@ struct Device
     int delta = bits & mask;
 
     if ((unsigned int) delta >= ((mask + 1) >> 1))
       delta -= mask + 1;
 
     return delta;
   }
 
-  inline unsigned int get_size () const
+  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 ();
@@ -619,9 +593,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);
 };
 
 
+HB_BEGIN_DECLS
+HB_END_DECLS
+
 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-private.hh
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,24 +18,27 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_GDEF_PRIVATE_HH
 #define HB_OT_LAYOUT_GDEF_PRIVATE_HH
 
 #include "hb-ot-layout-common-private.hh"
 
-#include "hb-font-private.hh"
+#include "hb-font-private.h"
+
+HB_BEGIN_DECLS
 
 
 /*
  * Attachment List Table
  */
 
 typedef ArrayOf<USHORT> AttachPoint;	/* Array of contour point indices--in
 					 * increasing numerical order */
@@ -87,20 +91,19 @@ struct AttachList
  * Ligature Caret Table
  */
 
 struct CaretValueFormat1
 {
   friend struct CaretValue;
 
   private:
-  inline int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id HB_UNUSED) const
+  inline int get_caret_value (hb_ot_layout_context_t *c, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
   {
-    /* TODO vertical */
-    return c->scale_x (coordinate);
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? c->scale_x (coordinate) : c->scale_y (coordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return c->check_struct (this);
   }
 
   private:
@@ -110,22 +113,21 @@ struct CaretValueFormat1
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat2
 {
   friend struct CaretValue;
 
   private:
-  inline int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id) const
+  inline int get_caret_value (hb_ot_layout_context_t *c, hb_direction_t direction, hb_codepoint_t glyph_id) const
   {
-    /* TODO vertical */
     hb_position_t x, y;
     if (hb_font_get_contour_point (c->font, c->face, caretValuePoint, glyph_id, &x, &y))
-      return x;
+      return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
     else
       return 0;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return c->check_struct (this);
   }
@@ -136,20 +138,21 @@ struct CaretValueFormat2
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct CaretValueFormat3
 {
   friend struct CaretValue;
 
-  inline int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id HB_UNUSED) const
+  inline int get_caret_value (hb_ot_layout_context_t *c, hb_direction_t direction, hb_codepoint_t glyph_id) const
   {
-    /* TODO vertical */
-    return c->scale_x (coordinate) + ((this+deviceTable).get_x_delta (c));
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
+           c->scale_x (coordinate) + (this+deviceTable).get_x_delta (c) :
+           c->scale_y (coordinate) + (this+deviceTable).get_y_delta (c);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return c->check_struct (this)
 	&& deviceTable.sanitize (c, this);
   }
 
@@ -161,22 +164,22 @@ struct CaretValueFormat3
 					 * value--from beginning of CaretValue
 					 * table */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct CaretValue
 {
-  inline int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id) const
+  inline int get_caret_value (hb_ot_layout_context_t *c, hb_direction_t direction, hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_caret_value (c, glyph_id);
-    case 2: return u.format2.get_caret_value (c, glyph_id);
-    case 3: return u.format3.get_caret_value (c, glyph_id);
+    case 1: return u.format1.get_caret_value (c, direction, glyph_id);
+    case 2: return u.format2.get_caret_value (c, direction, glyph_id);
+    case 3: return u.format3.get_caret_value (c, direction, glyph_id);
     default:return 0;
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!u.format.sanitize (c)) return false;
     switch (u.format) {
@@ -196,26 +199,27 @@ struct CaretValue
   } u;
   public:
   DEFINE_SIZE_UNION (2, format);
 };
 
 struct LigGlyph
 {
   inline unsigned int get_lig_carets (hb_ot_layout_context_t *c,
+				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      int *caret_array /* OUT */) const
   {
     if (caret_count) {
       const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
       unsigned int count = *caret_count;
       for (unsigned int i = 0; i < count; i++)
-	caret_array[i] = (this+array[i]).get_caret_value (c, glyph_id);
+	caret_array[i] = (this+array[i]).get_caret_value (c, direction, glyph_id);
     }
 
     return carets.len;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return carets.sanitize (c, this);
@@ -228,30 +232,31 @@ struct LigGlyph
 					 * --in increasing coordinate order */
   public:
   DEFINE_SIZE_ARRAY (2, carets);
 };
 
 struct LigCaretList
 {
   inline unsigned int get_lig_carets (hb_ot_layout_context_t *c,
+				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      int *caret_array /* OUT */) const
   {
     unsigned int index = (this+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 (c, glyph_id, start_offset, caret_count, caret_array);
+    return lig_glyph.get_lig_carets (c, direction, glyph_id, start_offset, caret_count, caret_array);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& ligGlyph.sanitize (c, this);
   }
 
@@ -326,53 +331,75 @@ struct GDEF
   enum {
     UnclassifiedGlyph	= 0,
     BaseGlyph		= 1,
     LigatureGlyph	= 2,
     MarkGlyph		= 3,
     ComponentGlyph	= 4
   };
 
-  inline bool has_glyph_classes () const { return glyphClassDef != 0; }
-  inline hb_ot_layout_class_t get_glyph_class (hb_codepoint_t glyph) const
+  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 bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
-  inline hb_ot_layout_class_t get_mark_attachment_type (hb_codepoint_t glyph) const
+  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 () const { return attachList != 0; }
+  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,
 					 unsigned int *point_count /* IN/OUT */,
 					 unsigned int *point_array /* OUT */) const
   { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
 
-  inline bool has_lig_carets () const { return ligCaretList != 0; }
+  inline bool has_lig_carets (void) const { return ligCaretList != 0; }
   inline unsigned int get_lig_carets (hb_ot_layout_context_t *c,
+				      hb_direction_t direction,
 				      hb_codepoint_t glyph_id,
 				      unsigned int start_offset,
 				      unsigned int *caret_count /* IN/OUT */,
 				      int *caret_array /* OUT */) const
-  { return (this+ligCaretList).get_lig_carets (c, glyph_id, start_offset, caret_count, caret_array); }
+  { return (this+ligCaretList).get_lig_carets (c, direction, glyph_id, start_offset, caret_count, caret_array); }
 
-  inline bool has_mark_sets () const { return version >= 0x00010002 && markGlyphSetsDef[0] != 0; }
+  inline bool has_mark_sets (void) const { return version >= 0x00010002 && markGlyphSetsDef[0] != 0; }
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return version >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     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 < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this));
   }
 
+
+  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
+   * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
+   * Not to be confused with lookup_props which is very similar. */
+  inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
+  {
+    unsigned int klass = get_glyph_class (glyph);
+
+    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 MarkGlyph:
+	  klass = get_mark_attachment_type (glyph);
+	  return HB_OT_LAYOUT_GLYPH_CLASS_MARK | (klass << 8);
+    }
+  }
+
+
   private:
   FixedVersion	version;		/* Version of the GDEF table--currently
 					 * 0x00010002 */
   OffsetTo<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
 					 * for glyph type--from beginning of
 					 * GDEF header (may be Null) */
   OffsetTo<AttachList>
@@ -392,9 +419,11 @@ struct GDEF
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 00010002. */
   public:
   DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
 };
 
 
+HB_END_DECLS
+
 #endif /* HB_OT_LAYOUT_GDEF_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,25 +18,31 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH
 #define HB_OT_LAYOUT_GPOS_PRIVATE_HH
 
 #include "hb-ot-layout-gsubgpos-private.hh"
 
+HB_BEGIN_DECLS
 
-#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
+
+/* buffer var allocations */
+#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
+#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
+
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
 
 typedef USHORT Value;
 
 typedef Value ValueRecord[VAR];
 
 struct ValueFormat : USHORT
@@ -77,25 +84,25 @@ struct ValueFormat : USHORT
   Offset	xAdvDevice;		/* Offset to Device table for
 					 * horizontal advance--measured from
 					 * beginning of PosTable (may be NULL) */
   Offset	yAdvDevice;		/* Offset to Device table for vertical
 					 * advance--measured from beginning of
 					 * PosTable (may be NULL) */
 #endif
 
-  inline unsigned int get_len () const
+  inline unsigned int get_len (void) const
   { return _hb_popcount32 ((unsigned int) *this); }
-  inline unsigned int get_size () const
+  inline unsigned int get_size (void) const
   { return get_len () * Value::static_size; }
 
-  void apply_value (hb_ot_layout_context_t       *layout,
-		    const void                   *base,
-		    const Value                  *values,
-		    hb_internal_glyph_position_t &glyph_pos) const
+  void apply_value (hb_ot_layout_context_t *layout,
+		    const void             *base,
+		    const Value            *values,
+		    hb_glyph_position_t    &glyph_pos) const
   {
     unsigned int x_ppem, y_ppem;
     unsigned int format = *this;
 
     if (!format) return;
 
     /* design units -> fractional pixel */
     if (format & xPlacement) glyph_pos.x_offset  += layout->scale_x (get_short (values++));
@@ -147,17 +154,17 @@ struct ValueFormat : USHORT
   static inline const OffsetTo<Device>& get_device (const Value* value)
   { return *CastP<OffsetTo<Device> > (value); }
 
   static inline const SHORT& get_short (const Value* value)
   { return *CastP<SHORT> (value); }
 
   public:
 
-  inline bool has_device () const {
+  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 ();
     return c->check_range (values, get_size ())
 	&& (!has_device () || sanitize_value_devices (c, base, values));
@@ -228,17 +235,17 @@ struct AnchorFormat2
 
   private:
   inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
 			  hb_position_t *x, hb_position_t *y) const
   {
       unsigned int x_ppem = layout->font->x_ppem;
       unsigned int y_ppem = layout->font->y_ppem;
       hb_position_t cx, cy;
-      hb_bool_t ret;
+      hb_bool_t ret = false;
 
       if (x_ppem || y_ppem)
 	ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
       *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
       *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
@@ -394,20 +401,20 @@ struct MarkArray : ArrayOf<MarkRecord>	/
     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;
 
     mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
     glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
-    hb_internal_glyph_position_t &o = c->buffer->pos[c->buffer->i];
-    o.x_offset  = base_x - mark_x;
-    o.y_offset  = base_y - mark_y;
-    o.back      = c->buffer->i - glyph_pos;
+    hb_glyph_position_t &o = c->buffer->pos[c->buffer->i];
+    o.x_offset = base_x - mark_x;
+    o.y_offset = base_y - mark_y;
+    o.attach_lookback() = c->buffer->i - glyph_pos;
 
     c->buffer->i++;
     return true;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return ArrayOf<MarkRecord>::sanitize (c, this);
@@ -618,17 +625,17 @@ struct PairPosFormat1
     if (unlikely (c->buffer->i + 2 > end))
       return false;
 
     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
     unsigned int j = c->buffer->i + 1;
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j == end))
 	return false;
       j++;
     }
 
     return (this+pairSet[index]).apply (c, &valueFormat1, j);
   }
@@ -680,17 +687,17 @@ struct PairPosFormat2
     if (unlikely (c->buffer->i + 2 > end))
       return false;
 
     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
     unsigned int j = c->buffer->i + 1;
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j == end))
 	return false;
       j++;
     }
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
@@ -819,185 +826,84 @@ struct EntryExitRecord
 struct CursivePosFormat1
 {
   friend struct CursivePos;
 
   private:
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
-    /* Now comes the messiest part of the whole OpenType
-       specification.  At first glance, cursive connections seem easy
-       to understand, but there are pitfalls!  The reason is that
-       the specs don't mention how to compute the advance values
-       resp. glyph offsets.  I was told it would be an omission, to
-       be fixed in the next OpenType version...  Again many thanks to
-       Andrei Burago <andreib@microsoft.com> for clarifications.
-
-       Consider the following example:
-
-			|  xadv1    |
-			 +---------+
-			 |         |
-		   +-----+--+ 1    |
-		   |     | .|      |
-		   |    0+--+------+
-		   |   2    |
-		   |        |
-		  0+--------+
-		  |  xadv2   |
-
-	 glyph1: advance width = 12
-		 anchor point = (3,1)
-
-	 glyph2: advance width = 11
-		 anchor point = (9,4)
-
-	 LSB is 1 for both glyphs (so the boxes drawn above are glyph
-	 bboxes).  Writing direction is R2L; `0' denotes the glyph's
-	 coordinate origin.
-
-       Now the surprising part: The advance width of the *left* glyph
-       (resp. of the *bottom* glyph) will be modified, no matter
-       whether the writing direction is L2R or R2L (resp. T2B or
-       B2T)!  This assymetry is caused by the fact that the glyph's
-       coordinate origin is always the lower left corner for all
-       writing directions.
-
-       Continuing the above example, we can compute the new
-       (horizontal) advance width of glyph2 as
-
-	 9 - 3 = 6  ,
-
-       and the new vertical offset of glyph2 as
-
-	 1 - 4 = -3  .
-
-
-       Vertical writing direction is far more complicated:
-
-       a) Assuming that we recompute the advance height of the lower glyph:
-
-				    --
-			 +---------+
-		--       |         |
-		   +-----+--+ 1    | yadv1
-		   |     | .|      |
-	     yadv2 |    0+--+------+        -- BSB1  --
-		   |   2    |       --      --        y_offset
-		   |        |
-     BSB2 --      0+--------+                        --
-	  --    --
-
-	 glyph1: advance height = 6
-		 anchor point = (3,1)
-
-	 glyph2: advance height = 7
-		 anchor point = (9,4)
-
-	 TSB is 1 for both glyphs; writing direction is T2B.
-
-
-	   BSB1     = yadv1 - (TSB1 + ymax1)
-	   BSB2     = yadv2 - (TSB2 + ymax2)
-	   y_offset = y2 - y1
-
-	 vertical advance width of glyph2
-	   = y_offset + BSB2 - BSB1
-	   = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
-	   = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
-	   = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
-
-
-       b) Assuming that we recompute the advance height of the upper glyph:
-
-				    --      --
-			 +---------+        -- TSB1
-	  --    --       |         |
-     TSB2 --       +-----+--+ 1    | yadv1   ymax1
-		   |     | .|      |
-	     yadv2 |    0+--+------+        --       --
-      ymax2        |   2    |       --                y_offset
-		   |        |
-	  --      0+--------+                        --
-		--
-
-	 glyph1: advance height = 6
-		 anchor point = (3,1)
-
-	 glyph2: advance height = 7
-		 anchor point = (9,4)
-
-	 TSB is 1 for both glyphs; writing direction is T2B.
-
-	 y_offset = y2 - y1
-
-	 vertical advance width of glyph2
-	   = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
-	   = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
-
-
-       Comparing a) with b) shows that b) is easier to compute.  I'll wait
-       for a reply from Andrei to see what should really be implemented...
-
-       Since horizontal advance widths or vertical advance heights
-       can be used alone but not together, no ambiguity occurs.        */
-
-    struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
-    hb_codepoint_t last_pos = gpi->last;
-    gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
 
     /* We don't handle mark glyphs here. */
-    if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+    if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
       return false;
 
-    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
-    if (likely (index == NOT_COVERED))
+    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+    if (unlikely (c->buffer->i + 2 > end))
+      return false;
+
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)];
+    if (!this_record.exitAnchor)
       return false;
 
-    const EntryExitRecord &record = entryExitRecord[index];
+    unsigned int j = c->buffer->i + 1;
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
+    {
+      if (unlikely (j == end))
+	return false;
+      j++;
+    }
 
-    if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
-      goto end;
+    const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)];
+    if (!next_record.entryAnchor)
+      return false;
+
+    unsigned int i = c->buffer->i;
 
-    hb_position_t entry_x, entry_y;
-    (this+record.entryAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &entry_x, &entry_y);
+    hb_position_t entry_x, entry_y, exit_x, exit_y;
+    (this+this_record.exitAnchor).get_anchor (c->layout, c->buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+next_record.entryAnchor).get_anchor (c->layout, c->buffer->info[j].codepoint, &entry_x, &entry_y);
 
-    /* TODO vertical */
+    hb_direction_t direction = c->buffer->props.direction;
 
-    if (c->buffer->direction == HB_DIRECTION_RTL)
+    /* Align the exit anchor of the left/top glyph with the entry anchor of the right/bottom glyph
+     * by adjusting advance of the left/top glyph. */
+    if (HB_DIRECTION_IS_BACKWARD (direction))
     {
-      /* advance is absolute, not relative */
-      c->buffer->pos[c->buffer->i].x_advance = entry_x - gpi->anchor_x;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+	c->buffer->pos[j].x_advance = c->buffer->pos[j].x_offset + entry_x - exit_x;
+      else
+	c->buffer->pos[j].y_advance = c->buffer->pos[j].y_offset + entry_y - exit_y;
     }
     else
     {
-      /* advance is absolute, not relative */
-      c->buffer->pos[last_pos].x_advance = gpi->anchor_x - entry_x;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+	c->buffer->pos[i].x_advance = c->buffer->pos[i].x_offset + exit_x - entry_x;
+      else
+	c->buffer->pos[i].y_advance = c->buffer->pos[i].y_offset + exit_y - entry_y;
     }
 
-    if  (c->lookup_flag & LookupFlag::RightToLeft)
+    if  (c->lookup_props & LookupFlag::RightToLeft)
     {
-      c->buffer->pos[last_pos].cursive_chain = last_pos - c->buffer->i;
-      c->buffer->pos[last_pos].y_offset = entry_y - gpi->anchor_y;
+      c->buffer->pos[i].cursive_chain() = j - i;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+	c->buffer->pos[i].y_offset = entry_y - exit_y;
+      else
+	c->buffer->pos[i].x_offset = entry_x - exit_x;
     }
     else
     {
-      c->buffer->pos[c->buffer->i].cursive_chain = c->buffer->i - last_pos;
-      c->buffer->pos[c->buffer->i].y_offset = gpi->anchor_y - entry_y;
+      c->buffer->pos[j].cursive_chain() = i - j;
+      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+	c->buffer->pos[j].y_offset = exit_y - entry_y;
+      else
+	c->buffer->pos[j].x_offset = exit_x - entry_x;
     }
 
-  end:
-    if (record.exitAnchor)
-    {
-      gpi->last = c->buffer->i;
-      (this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &gpi->anchor_x, &gpi->anchor_y);
-    }
-
-    c->buffer->i++;
+    c->buffer->i = j;
     return true;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& entryExitRecord.sanitize (c, this);
   }
@@ -1068,18 +974,18 @@ struct MarkBasePosFormat1
     do
     {
       if (unlikely (!j))
 	return false;
       j--;
     } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
-      return false;
+    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
+    {/*return false;*/}
 
     unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
     if (base_index == NOT_COVERED)
       return false;
 
     return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
   }
 
@@ -1170,18 +1076,18 @@ struct MarkLigPosFormat1
     do
     {
       if (unlikely (!j))
 	return false;
       j--;
     } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
 
     /* The following assertion is too strong, so we've disabled it. */
-    if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
-      return false;
+    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
+    {/*return false;*/}
 
     unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
     if (lig_index == NOT_COVERED)
       return false;
 
     const LigatureArray& lig_array = this+ligatureArray;
     const LigatureAttach& lig_attach = lig_array[lig_index];
 
@@ -1189,19 +1095,19 @@ struct MarkLigPosFormat1
     unsigned int comp_count = lig_attach.rows;
     if (unlikely (!comp_count))
       return false;
     unsigned int comp_index;
     /* We must now check whether the ligature ID of the current mark glyph
      * is identical to the ligature ID of the found ligature.  If yes, we
      * can directly use the component index.  If not, we attach the mark
      * glyph to the last component of the ligature. */
-    if (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->i].lig_id && c->buffer->info[c->buffer->i].component)
+    if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->i].lig_id() && c->buffer->info[c->buffer->i].lig_comp())
     {
-      comp_index = c->buffer->info[c->buffer->i].component - 1;
+      comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1;
       if (comp_index >= comp_count)
 	comp_index = comp_count - 1;
     }
     else
       comp_index = comp_count - 1;
 
     return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
   }
@@ -1286,26 +1192,26 @@ struct MarkMarkPosFormat1
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
     unsigned int property;
     unsigned int j = c->buffer->i;
     do
     {
       if (unlikely (!j))
 	return false;
       j--;
-    } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
+    } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, &property));
 
     if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
       return false;
 
     /* Two marks match only if they belong to the same base, or same component
      * of the same ligature.  That is, the component numbers must match, and
      * if those are non-zero, the ligid number should also match. */
-    if ((c->buffer->info[j].component != c->buffer->info[c->buffer->i].component) ||
-	(c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->i].lig_id))
+    if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp()) ||
+	(c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id()))
       return false;
 
     unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
     if (mark2_index == NOT_COVERED)
       return false;
 
     return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
   }
@@ -1366,17 +1272,19 @@ struct MarkMarkPos
   private:
   union {
   USHORT		format;		/* Format identifier */
   MarkMarkPosFormat1	format1;
   } u;
 };
 
 
+HB_BEGIN_DECLS
 static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
+HB_END_DECLS
 
 struct ContextPos : Context
 {
   friend struct PosLookupSubTable;
 
   private:
   inline bool apply (hb_apply_context_t *c) const
   {
@@ -1503,19 +1411,19 @@ struct PosLookup : Lookup
     unsigned int lookup_type = get_type ();
     hb_apply_context_t c[1] = {{0}};
 
     c->layout = layout;
     c->buffer = buffer;
     c->lookup_mask = lookup_mask;
     c->context_length = context_length;
     c->nesting_level_left = nesting_level_left;
-    c->lookup_flag = get_flag ();
+    c->lookup_props = get_props ();
 
-    if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
+    if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
       return false;
 
     for (unsigned int i = 0; i < get_subtable_count (); i++)
       if (get_subtable (i).apply (c, lookup_type))
 	return true;
 
     return false;
   }
@@ -1524,36 +1432,23 @@ struct PosLookup : Lookup
 			     hb_buffer_t *buffer,
 			     hb_mask_t    mask) const
   {
     bool ret = false;
 
     if (unlikely (!buffer->len))
       return false;
 
-    layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
-
     buffer->i = 0;
     while (buffer->i < buffer->len)
     {
-      bool done;
-      if (buffer->info[buffer->i].mask & mask)
-      {
-	  done = apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL);
-	  ret |= done;
-      }
+      if ((buffer->info[buffer->i].mask & mask) &&
+	  apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+	ret = true;
       else
-      {
-          done = false;
-	  /* Contrary to properties defined in GDEF, user-defined properties
-	     will always stop a possible cursive positioning.                */
-	  layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
-      }
-
-      if (!done)
 	buffer->i++;
     }
 
     return ret;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
@@ -1577,26 +1472,85 @@ struct GPOS : GSUBGPOS
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
   inline bool position_lookup (hb_ot_layout_context_t *layout,
 			       hb_buffer_t  *buffer,
 			       unsigned int  lookup_index,
 			       hb_mask_t     mask) const
   { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
 
+  static inline void position_finish (hb_buffer_t *buffer);
+
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (unlikely (!GSUBGPOS::sanitize (c))) return false;
     OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
     return list.sanitize (c, this);
   }
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
+void
+GPOS::position_finish (hb_buffer_t *buffer)
+{
+  unsigned int i, j;
+  unsigned int len = hb_buffer_get_length (buffer);
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer);
+  hb_direction_t direction = buffer->props.direction;
+
+  /* Handle cursive connections:
+   * First handle all chain-back connections, then handle all chain-forward connections. */
+  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+  {
+    for (j = 0; j < len; j++) {
+      if (pos[j].cursive_chain() < 0)
+	pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset;
+    }
+    for (i = len; i > 0; i--) {
+      j = i - 1;
+      if (pos[j].cursive_chain() > 0)
+	pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset;
+    }
+  }
+  else
+  {
+    for (j = 0; j < len; j++) {
+      if (pos[j].cursive_chain() < 0)
+	pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset;
+    }
+    for (i = len; i > 0; i--) {
+      j = i - 1;
+      if (pos[j].cursive_chain() > 0)
+	pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset;
+    }
+  }
+
+
+  /* Handle attachments */
+  for (i = 0; i < len; i++)
+    if (pos[i].attach_lookback())
+    {
+      unsigned int back = i - pos[i].attach_lookback();
+      pos[i].x_offset += pos[back].x_offset;
+      pos[i].y_offset += pos[back].y_offset;
+
+      if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+	for (j = back + 1; j < i + 1; j++) {
+	  pos[i].x_offset += pos[j].x_advance;
+	  pos[i].y_offset += pos[j].y_advance;
+	}
+      else
+	for (j = back; j < i; j++) {
+	  pos[i].x_offset -= pos[j].x_advance;
+	  pos[i].y_offset -= pos[j].y_advance;
+	}
+    }
+}
+
 
 /* Out-of-class implementation for methods recursing */
 
 inline bool ExtensionPos::apply (hb_apply_context_t *c) const
 {
   TRACE_APPLY ();
   return get_subtable ().apply (c, get_type ());
 }
@@ -1620,9 +1574,15 @@ static inline bool position_lookup (hb_a
 
   if (unlikely (c->context_length < 1))
     return false;
 
   return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
 }
 
 
+#undef attach_lookback
+#undef cursive_chain
+
+
+HB_END_DECLS
+
 #endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,44 +18,43 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_GSUB_PRIVATE_HH
 #define HB_OT_LAYOUT_GSUB_PRIVATE_HH
 
 #include "hb-ot-layout-gsubgpos-private.hh"
 
+HB_BEGIN_DECLS
+
 
 struct SingleSubstFormat1
 {
   friend struct SingleSubst;
 
   private:
 
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
       return false;
 
     glyph_id += deltaGlyphID;
-    c->buffer->replace_glyph (glyph_id);
-
-    /* We inherit the old glyph class to the substituted glyph */
-    if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
-      _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+    c->replace_glyph (glyph_id);
 
     return true;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& deltaGlyphID.sanitize (c);
@@ -84,21 +84,17 @@ struct SingleSubstFormat2
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
       return false;
 
     if (unlikely (index >= substitute.len))
       return false;
 
     glyph_id = substitute[index];
-    c->buffer->replace_glyph (glyph_id);
-
-    /* We inherit the old glyph class to the substituted glyph */
-    if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
-      _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+    c->replace_glyph (glyph_id);
 
     return true;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& substitute.sanitize (c);
@@ -157,31 +153,19 @@ struct Sequence
 
   private:
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     if (unlikely (!substitute.len))
       return false;
 
-    c->buffer->add_output_glyphs_be16 (1,
-				       substitute.len, (const uint16_t *) substitute.array,
-				       0xFFFF, 0xFFFF);
-
-    /* This is a guess only ... */
-    if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
-    {
-      unsigned int property = c->property;
-      if (property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
-        property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
-
-      unsigned int count = substitute.len;
-      for (unsigned int n = 0; n < count; n++)
-	_hb_ot_layout_set_glyph_property (c->layout->face, substitute[n], property);
-    }
+    if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
+      c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH);
+    c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array);
 
     return true;
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return substitute.sanitize (c);
@@ -290,21 +274,17 @@ struct AlternateSubstFormat1
     unsigned int shift = _hb_ctz (lookup_mask);
     unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
 
     if (unlikely (alt_index > alt_set.len || alt_index == 0))
       return false;
 
     glyph_id = alt_set[alt_index - 1];
 
-    c->buffer->replace_glyph (glyph_id);
-
-    /* We inherit the old glyph class to the substituted glyph */
-    if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
-      _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+    c->replace_glyph (glyph_id);
 
     return true;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& alternateSet.sanitize (c, this);
@@ -354,79 +334,90 @@ struct AlternateSubst
 };
 
 
 struct Ligature
 {
   friend struct LigatureSet;
 
   private:
-  inline bool apply (hb_apply_context_t *c, bool is_mark) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     unsigned int i, j;
     unsigned int count = component.len;
     unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
     if (unlikely (c->buffer->i + count > end))
       return false;
 
+    bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+    bool found_non_mark = false;
+
     for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
     {
       unsigned int property;
-      while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property))
+      while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, &property))
       {
 	if (unlikely (j + count - i == end))
 	  return false;
 	j++;
       }
 
-      if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
-	is_mark = false;
+      found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
 
       if (likely (c->buffer->info[j].codepoint != component[i]))
         return false;
     }
-    /* This is just a guess ... */
-    if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
-      _hb_ot_layout_set_glyph_class (c->layout->face, ligGlyph,
-				     is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
-					     : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
+
+    if (first_was_mark && found_non_mark)
+      c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
+
+    /* Allocate new ligature id */
+    unsigned int lig_id = allocate_lig_id (c->buffer);
+    c->buffer->info[c->buffer->i].lig_comp() = 0;
+    c->buffer->info[c->buffer->i].lig_id() = lig_id;
 
     if (j == c->buffer->i + i) /* No input glyphs skipped */
-      /* We don't use a new ligature ID if there are no skipped
-	 glyphs and the ligature already has an ID. */
-      c->buffer->add_output_glyphs_be16 (i,
-					 1, (const uint16_t *) &ligGlyph,
-					 0,
-					 c->buffer->info[c->buffer->i].lig_id && !c->buffer->info[c->buffer->i].component ?
-					 0xFFFF : c->buffer->allocate_lig_id ());
+    {
+      c->replace_glyphs_be16 (i, 1, (const uint16_t *) &ligGlyph);
+    }
     else
     {
-      unsigned int lig_id = c->buffer->allocate_lig_id ();
-      c->buffer->add_output_glyph (ligGlyph, 0xFFFF, lig_id);
+      c->replace_glyph (ligGlyph);
 
       /* Now we must do a second loop to copy the skipped glyphs to
 	 `out' and assign component values to it.  We start with the
 	 glyph after the first component.  Glyphs between component
 	 i and i+1 belong to component i.  Together with the lig_id
 	 value it is later possible to check whether a specific
 	 component value really belongs to a given ligature. */
 
-      for ( i = 1; i < count; i++ )
+      for (i = 1; i < count; i++)
       {
-	while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, NULL))
-	  c->buffer->add_output_glyph (c->buffer->info[c->buffer->i].codepoint, i, lig_id);
+	while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL))
+	{
+	  c->buffer->info[c->buffer->i].lig_comp() = i;
+	  c->buffer->info[c->buffer->i].lig_id() = lig_id;
+	  c->replace_glyph (c->buffer->info[c->buffer->i].codepoint);
+	}
 
-	(c->buffer->i)++;
+	/* Skip the base glyph */
+	c->buffer->i++;
       }
     }
 
     return true;
   }
 
+  inline uint16_t allocate_lig_id (hb_buffer_t *buffer) const {
+    uint16_t lig_id = buffer->next_serial ();
+    if (unlikely (!lig_id)) lig_id = buffer->next_serial (); /* in case of overflows */
+    return lig_id;
+  }
+
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return ligGlyph.sanitize (c)
         && component.sanitize (c);
   }
 
   private:
@@ -439,24 +430,24 @@ struct Ligature
   DEFINE_SIZE_ARRAY (4, component);
 };
 
 struct LigatureSet
 {
   friend struct LigatureSubstFormat1;
 
   private:
-  inline bool apply (hb_apply_context_t *c, bool is_mark) const
+  inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     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, is_mark))
+      if (lig.apply (c))
         return true;
     }
 
     return false;
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
@@ -477,24 +468,22 @@ struct LigatureSubstFormat1
   friend struct LigatureSubst;
 
   private:
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY ();
     hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
 
-    bool first_is_mark = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
-
     unsigned int index = (this+coverage) (glyph_id);
     if (likely (index == NOT_COVERED))
       return false;
 
     const LigatureSet &lig_set = this+ligatureSet[index];
-    return lig_set.apply (c, first_is_mark);
+    return lig_set.apply (c);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     return coverage.sanitize (c, this)
 	&& ligatureSet.sanitize (c, this);
   }
 
@@ -536,18 +525,19 @@ struct LigatureSubst
   private:
   union {
   USHORT		format;		/* Format identifier */
   LigatureSubstFormat1	format1;
   } u;
 };
 
 
-
+HB_BEGIN_DECLS
 static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
+HB_END_DECLS
 
 struct ContextSubst : Context
 {
   friend struct SubstLookupSubTable;
 
   private:
   inline bool apply (hb_apply_context_t *c) const
   {
@@ -781,19 +771,19 @@ struct SubstLookup : Lookup
     unsigned int lookup_type = get_type ();
     hb_apply_context_t c[1] = {{0}};
 
     c->layout = layout;
     c->buffer = buffer;
     c->lookup_mask = lookup_mask;
     c->context_length = context_length;
     c->nesting_level_left = nesting_level_left;
-    c->lookup_flag = get_flag ();
+    c->lookup_props = get_props ();
 
-    if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
+    if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
       return false;
 
     if (unlikely (lookup_type == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables should have the same type.
        * This is specially important if one has a reverse type!
        *
        * This is rather slow to do this here for every glyph,
@@ -931,9 +921,11 @@ static inline bool substitute_lookup (hb
 
   if (unlikely (c->context_length < 1))
     return false;
 
   return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
 }
 
 
+HB_END_DECLS
+
 #endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,43 +18,80 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
 
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-private.hh"
 
+HB_BEGIN_DECLS
+
+
+/* buffer var allocations */
+#define lig_id() var2.u16[0] /* unique ligature id */
+#define lig_comp() var2.u16[1] /* component number in the ligature (0 = base) */
+
 
 #ifndef HB_DEBUG_APPLY
-#define HB_DEBUG_APPLY HB_DEBUG+0
+#define HB_DEBUG_APPLY (HB_DEBUG+0)
 #endif
 
 #define TRACE_APPLY() \
 	hb_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", HB_FUNC, this); \
 
 
+HB_BEGIN_DECLS
+
 struct hb_apply_context_t
 {
   unsigned int debug_depth;
   hb_ot_layout_context_t *layout;
   hb_buffer_t *buffer;
   hb_mask_t lookup_mask;
   unsigned int context_length;
   unsigned int nesting_level_left;
-  unsigned int lookup_flag;
-  unsigned int property; /* propety of first glyph (TODO remove) */
+  unsigned int lookup_props;
+  unsigned int property; /* propety of first glyph */
+
+
+  inline void replace_glyph (hb_codepoint_t glyph_index) const
+  {
+    clear_property ();
+    buffer->replace_glyph (glyph_index);
+  }
+  inline void replace_glyphs_be16 (unsigned int num_in,
+				   unsigned int num_out,
+				   const uint16_t *glyph_data_be) const
+  {
+    clear_property ();
+    buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
+  }
+
+  inline void guess_glyph_class (unsigned int klass)
+  {
+    /* XXX if ! has gdef */
+    buffer->info[buffer->i].props_cache() = klass;
+  }
+
+  private:
+  inline void clear_property (void) const
+  {
+    /* XXX if has gdef */
+    buffer->info[buffer->i].props_cache() = 0;
+  }
 };
 
 
 
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
 typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
 
 struct ContextFuncs
@@ -90,17 +128,17 @@ static inline bool match_input (hb_apply
 {
   unsigned int i, j;
   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
   if (unlikely (c->buffer->i + count > end))
     return false;
 
   for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
   {
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j + count - i == end))
 	return false;
       j++;
     }
 
     if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_data)))
       return false;
@@ -117,17 +155,17 @@ static inline bool match_backtrack (hb_a
 				    match_func_t match_func,
 				    const void *match_data)
 {
   if (unlikely (c->buffer->out_len < count))
     return false;
 
   for (unsigned int i = 0, j = c->buffer->out_len - 1; i < count; i++, j--)
   {
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->out_info[j], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->out_info[j], c->lookup_props, NULL))
     {
       if (unlikely (j + 1 == count - i))
 	return false;
       j--;
     }
 
     if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], match_data)))
       return false;
@@ -145,46 +183,51 @@ static inline bool match_lookahead (hb_a
 {
   unsigned int i, j;
   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
   if (unlikely (c->buffer->i + offset + count > end))
     return false;
 
   for (i = 0, j = c->buffer->i + offset; i < count; i++, j++)
   {
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
     {
       if (unlikely (j + count - i == end))
 	return false;
       j++;
     }
 
     if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_data)))
       return false;
   }
 
   return true;
 }
 
+HB_END_DECLS
+
 
 struct LookupRecord
 {
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     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);
 };
 
+
+HB_BEGIN_DECLS
+
 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)
 {
   unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
   if (unlikely (c->buffer->i + count > end))
@@ -194,17 +237,17 @@ static inline bool apply_lookup (hb_appl
    *      Should be easy for in_place ones at least. */
 
   /* Note: If sublookup is reverse, i will underflow after the first loop
    * and we jump out of it.  Not entirely disastrous.  So we don't check
    * for reverse lookup here.
    */
   for (unsigned int i = 0; i < count; /* NOP */)
   {
-    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, NULL))
+    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL))
     {
       if (unlikely (c->buffer->i == end))
 	return true;
       /* No lookup applied for this index */
       c->buffer->next_glyph ();
     }
 
     if (lookupCount && i == lookupRecord->sequenceIndex)
@@ -231,16 +274,18 @@ static inline bool apply_lookup (hb_appl
       c->buffer->next_glyph ();
       i++;
     }
   }
 
   return true;
 }
 
+HB_END_DECLS
+
 
 /* Contextual lookups */
 
 struct ContextLookupContext
 {
   ContextFuncs funcs;
   const void *match_data;
 };
@@ -379,19 +424,16 @@ struct ContextFormat2
     TRACE_APPLY ();
     unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
     if (likely (index == NOT_COVERED))
       return false;
 
     const ClassDef &class_def = this+classDef;
     index = class_def (c->buffer->info[c->buffer->i].codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
-    /* LONGTERMTODO: Old code fetches glyph classes at most once and caches
-     * them across subrule lookups.  Not sure it's worth it.
-     */
     struct ContextLookupContext lookup_context = {
       {match_class, apply_func},
       &class_def
     };
     return rule_set.apply (c, lookup_context);
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
@@ -555,17 +597,16 @@ struct ChainRule
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return chain_context_lookup (c,
 				 backtrack.len, backtrack.array,
 				 input.len, input.array,
 				 lookahead.len, lookahead.array,
 				 lookup.len, lookup.array,
 				 lookup_context);
-    return false;
   }
 
   public:
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!backtrack.sanitize (c)) return false;
     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     if (!input.sanitize (c)) return false;
@@ -672,19 +713,16 @@ struct ChainContextFormat2
       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->info[c->buffer->i].codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
-    /* LONGTERMTODO: Old code fetches glyph classes at most once and caches
-     * them across subrule lookups.  Not sure it's worth it.
-     */
     struct ChainContextLookupContext lookup_context = {
       {match_class, apply_func},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
     };
     return rule_set.apply (c, lookup_context);
   }
@@ -744,17 +782,16 @@ struct ChainContextFormat3
       {this, this, this}
     };
     return chain_context_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);
-    return false;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE ();
     if (!backtrack.sanitize (c, this)) return false;
     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!input.sanitize (c, this)) return false;
     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
@@ -934,9 +971,11 @@ struct GSUBGPOS
 		featureList; 	/* FeatureList table */
   OffsetTo<LookupList>
 		lookupList; 	/* LookupList table */
   public:
   DEFINE_SIZE_STATIC (10);
 };
 
 
+HB_END_DECLS
+
 #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
@@ -19,105 +19,96 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_OT_LAYOUT_PRIVATE_H
-#define HB_OT_LAYOUT_PRIVATE_H
+#ifndef HB_OT_LAYOUT_PRIVATE_HH
+#define HB_OT_LAYOUT_PRIVATE_HH
 
 #include "hb-private.h"
 
 #include "hb-ot-layout.h"
+#include "hb-ot-head-private.hh"
 
-#include "hb-font-private.hh"
+#include "hb-font-private.h"
 #include "hb-buffer-private.hh"
 
-
 HB_BEGIN_DECLS
 
-typedef unsigned int hb_ot_layout_class_t;
+
+/* buffer var allocations */
+#define props_cache() var1.u16[1] /* glyph_props cache */
+
+
+/* XXX cleanup */
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0001,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
+} hb_ot_layout_glyph_class_t;
+
 
 /*
  * hb_ot_layout_t
  */
 
 struct hb_ot_layout_t
 {
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
 
   const struct GDEF *gdef;
   const struct GSUB *gsub;
   const struct GPOS *gpos;
-
-  struct
-  {
-    unsigned char *klasses;
-    unsigned int len;
-  } new_gdef;
 };
 
 struct hb_ot_layout_context_t
 {
   hb_face_t *face;
   hb_font_t *font;
 
-  union info_t
-  {
-    struct gpos_t
-    {
-      unsigned int last;        /* the last valid glyph--used with cursive positioning */
-      hb_position_t anchor_x;   /* the coordinates of the anchor point */
-      hb_position_t anchor_y;   /* of the last valid glyph */
-    } gpos;
-  } info;
+  /* Convert from font-space to user-space */
+  inline hb_position_t scale_x (int16_t v) { return scale (v, this->font->x_scale); }
+  inline hb_position_t scale_y (int16_t v) { return scale (v, this->font->y_scale); }
 
-  /* Convert from font-space to user-space */
-  /* XXX speed up */
-  inline hb_position_t scale_x (int16_t v) { return (int64_t) this->font->x_scale * v / this->face->units_per_em; }
-  inline hb_position_t scale_y (int16_t v) { return (int64_t) this->font->y_scale * v / this->face->units_per_em; }
+  private:
+  inline hb_position_t scale (int16_t v, unsigned int scale) { return v * (int64_t) scale / this->face->head_table->get_upem (); }
 };
 
 
 HB_INTERNAL hb_ot_layout_t *
 _hb_ot_layout_new (hb_face_t *face);
 
 HB_INTERNAL void
 _hb_ot_layout_free (hb_ot_layout_t *layout);
 
 
 /*
  * GDEF
  */
 
-HB_INTERNAL hb_bool_t
-_hb_ot_layout_has_new_glyph_classes (hb_face_t *face);
-
-HB_INTERNAL void
-_hb_ot_layout_set_glyph_property (hb_face_t      *face,
-				  hb_codepoint_t  glyph,
-				  unsigned int    property);
-
-HB_INTERNAL void
-_hb_ot_layout_set_glyph_class (hb_face_t                  *face,
-			       hb_codepoint_t              glyph,
-			       hb_ot_layout_glyph_class_t  klass);
+HB_INTERNAL unsigned int
+_hb_ot_layout_get_glyph_property (hb_face_t       *face,
+				  hb_glyph_info_t *info);
 
 HB_INTERNAL hb_bool_t
 _hb_ot_layout_check_glyph_property (hb_face_t    *face,
-				    hb_internal_glyph_info_t *ginfo,
-				    unsigned int  lookup_flags,
-				    unsigned int *property);
+				    hb_glyph_info_t *ginfo,
+				    unsigned int  lookup_props,
+				    unsigned int *property_out);
 
 HB_INTERNAL hb_bool_t
 _hb_ot_layout_skip_mark (hb_face_t    *face,
-			 hb_internal_glyph_info_t *ginfo,
-			 unsigned int  lookup_flags,
-			 unsigned int *property);
+			 hb_glyph_info_t *ginfo,
+			 unsigned int  lookup_props,
+			 unsigned int *property_out);
+
 
 HB_END_DECLS
 
-#endif /* HB_OT_LAYOUT_PRIVATE_H */
+#endif /* HB_OT_LAYOUT_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -33,16 +33,18 @@
 #include "hb-ot-layout-gdef-private.hh"
 #include "hb-ot-layout-gsub-private.hh"
 #include "hb-ot-layout-gpos-private.hh"
 
 
 #include <stdlib.h>
 #include <string.h>
 
+HB_BEGIN_DECLS
+
 
 hb_ot_layout_t *
 _hb_ot_layout_new (hb_face_t *face)
 {
   /* Remove this object altogether */
   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
 
   layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_get_table (face, HB_OT_TAG_GDEF));
@@ -63,271 +65,150 @@ void
   hb_blob_unlock (layout->gdef_blob);
   hb_blob_unlock (layout->gsub_blob);
   hb_blob_unlock (layout->gpos_blob);
 
   hb_blob_destroy (layout->gdef_blob);
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
-  free (layout->new_gdef.klasses);
+  free (layout);
 }
 
-static const GDEF&
+static inline const GDEF&
 _get_gdef (hb_face_t *face)
 {
   return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
 }
 
-static const GSUB&
+static inline const GSUB&
 _get_gsub (hb_face_t *face)
 {
   return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
 }
 
-static const GPOS&
+static inline const GPOS&
 _get_gpos (hb_face_t *face)
 {
   return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
 }
 
 
 /*
  * GDEF
  */
 
-/* TODO the public class_t is a mess */
-
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face)
 {
   return _get_gdef (face).has_glyph_classes ();
 }
 
-hb_bool_t
-_hb_ot_layout_has_new_glyph_classes (hb_face_t *face)
+unsigned int
+_hb_ot_layout_get_glyph_property (hb_face_t       *face,
+				  hb_glyph_info_t *info)
 {
-  return face->ot_layout->new_gdef.len > 0;
-}
-
-static unsigned int
-_hb_ot_layout_get_glyph_property (hb_face_t      *face,
-				  hb_codepoint_t  glyph)
-{
-  hb_ot_layout_class_t klass;
-  const GDEF &gdef = _get_gdef (face);
+  if (!info->props_cache())
+  {
+    const GDEF &gdef = _get_gdef (face);
+    info->props_cache() = gdef.get_glyph_props (info->codepoint);
+  }
 
-  klass = gdef.get_glyph_class (glyph);
-
-  if (!klass && glyph < face->ot_layout->new_gdef.len)
-    klass = face->ot_layout->new_gdef.klasses[glyph];
-
-  switch (klass) {
-  default:
-  case GDEF::UnclassifiedGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
-  case GDEF::BaseGlyph:		return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
-  case GDEF::LigatureGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
-  case GDEF::ComponentGlyph:	return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
-  case GDEF::MarkGlyph:
-	klass = gdef.get_mark_attachment_type (glyph);
-	return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
-  }
+  return info->props_cache();
 }
 
-hb_bool_t
-_hb_ot_layout_check_glyph_property (hb_face_t    *face,
-				    hb_internal_glyph_info_t *ginfo,
-				    unsigned int  lookup_flags,
-				    unsigned int *property_out)
+static hb_bool_t
+_hb_ot_layout_match_properties (hb_face_t      *face,
+				hb_codepoint_t  codepoint,
+				unsigned int    glyph_props,
+				unsigned int    lookup_props)
 {
-  unsigned int property;
-
-  if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
-    ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
-  property = ginfo->gproperty;
-  if (property_out)
-    *property_out = property;
-
   /* Not covered, if, for example, glyph class is ligature and
-   * lookup_flags includes LookupFlags::IgnoreLigatures
+   * lookup_props includes LookupFlags::IgnoreLigatures
    */
-  if (property & lookup_flags & LookupFlag::IgnoreFlags)
+  if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
     return false;
 
-  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+  if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
   {
     /* If using mark filtering sets, the high short of
-     * lookup_flags has the set index.
+     * lookup_props has the set index.
      */
-    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
-      return _get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
+    if (lookup_props & LookupFlag::UseMarkFilteringSet)
+      return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
 
-    /* The second byte of lookup_flags has the meaning
+    /* The second byte of lookup_props has the meaning
      * "ignore marks of attachment type different than
      * the attachment type specified."
      */
-    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
-      return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
+    if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
+      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
   }
 
   return true;
 }
 
 hb_bool_t
+_hb_ot_layout_check_glyph_property (hb_face_t    *face,
+				    hb_glyph_info_t *ginfo,
+				    unsigned int  lookup_props,
+				    unsigned int *property_out)
+{
+  unsigned int property;
+
+  property = _hb_ot_layout_get_glyph_property (face, ginfo);
+  (void) (property_out && (*property_out = property));
+
+  return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
+}
+
+hb_bool_t
 _hb_ot_layout_skip_mark (hb_face_t    *face,
-			 hb_internal_glyph_info_t *ginfo,
-			 unsigned int  lookup_flags,
+			 hb_glyph_info_t *ginfo,
+			 unsigned int  lookup_props,
 			 unsigned int *property_out)
 {
   unsigned int property;
 
-  if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
-    ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
-  property = ginfo->gproperty;
-  if (property_out)
-    *property_out = property;
+  property = _hb_ot_layout_get_glyph_property (face, ginfo);
+  (void) (property_out && (*property_out = property));
 
-  if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
-  {
-    /* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
-    if (lookup_flags & LookupFlag::IgnoreMarks)
-      return true;
+  /* If it's a mark, skip it we don't accept it. */
+  if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
+    return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
 
-    /* If using mark filtering sets, the high short of lookup_flags has the set index. */
-    if (lookup_flags & LookupFlag::UseMarkFilteringSet)
-      return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
-
-    /* The second byte of lookup_flags has the meaning "ignore marks of attachment type
-     * different than the attachment type specified." */
-    if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
-      return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
-  }
-
+  /* If not a mark, don't skip. */
   return false;
 }
 
-void
-_hb_ot_layout_set_glyph_class (hb_face_t                  *face,
-			       hb_codepoint_t              glyph,
-			       hb_ot_layout_glyph_class_t  klass)
-{
-  if (HB_OBJECT_IS_INERT (face))
-    return;
 
-  /* TODO optimize this? similar to old harfbuzz code for example */
-
-  hb_ot_layout_t *layout = face->ot_layout;
-  hb_ot_layout_class_t gdef_klass;
-  unsigned int len = layout->new_gdef.len;
-
-  if (unlikely (glyph > 65535))
-    return;
-
-  /* XXX this is not threadsafe */
-  if (glyph >= len) {
-    unsigned int new_len;
-    unsigned char *new_klasses;
-
-    new_len = len == 0 ? 120 : 2 * len;
-    while (new_len <= glyph)
-      new_len *= 2;
-
-    if (new_len > 65536)
-      new_len = 65536;
-    new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
-
-    if (unlikely (!new_klasses))
-      return;
-
-    memset (new_klasses + len, 0, new_len - len);
-
-    layout->new_gdef.klasses = new_klasses;
-    layout->new_gdef.len = new_len;
-  }
-
-  switch (klass) {
-  default:
-  case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED:	gdef_klass = GDEF::UnclassifiedGlyph;	break;
-  case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH:	gdef_klass = GDEF::BaseGlyph;		break;
-  case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE:	gdef_klass = GDEF::LigatureGlyph;	break;
-  case HB_OT_LAYOUT_GLYPH_CLASS_MARK:		gdef_klass = GDEF::MarkGlyph;		break;
-  case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT:	gdef_klass = GDEF::ComponentGlyph;	break;
-  }
-
-  layout->new_gdef.klasses[glyph] = gdef_klass;
-  return;
-}
-
-void
-_hb_ot_layout_set_glyph_property (hb_face_t      *face,
-				  hb_codepoint_t  glyph,
-				  unsigned int    property)
-{ _hb_ot_layout_set_glyph_class (face, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
-
-
-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) (_hb_ot_layout_get_glyph_property (face, glyph) & 0xff);
-}
-
-void
-hb_ot_layout_set_glyph_class (hb_face_t                 *face,
-			      hb_codepoint_t             glyph,
-			      hb_ot_layout_glyph_class_t klass)
-{
-  _hb_ot_layout_set_glyph_class (face, glyph, klass);
-}
-
-void
-hb_ot_layout_build_glyph_classes (hb_face_t      *face,
-				  hb_codepoint_t *glyphs,
-				  unsigned char  *klasses,
-				  uint16_t        count)
-{
-  if (HB_OBJECT_IS_INERT (face))
-    return;
-
-  hb_ot_layout_t *layout = face->ot_layout;
-
-  if (unlikely (!count || !glyphs || !klasses))
-    return;
-
-  if (layout->new_gdef.len == 0) {
-    layout->new_gdef.klasses = (unsigned char *) calloc (count, sizeof (unsigned char));
-    layout->new_gdef.len = count;
-  }
-
-  for (unsigned int i = 0; i < count; i++)
-    _hb_ot_layout_set_glyph_class (face, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
-}
 
 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 */)
 {
   return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
 }
 
 unsigned int
-hb_ot_layout_get_lig_carets (hb_font_t      *font,
-			     hb_face_t      *face,
-			     hb_codepoint_t  glyph,
-			     unsigned int    start_offset,
-			     unsigned int   *caret_count /* IN/OUT */,
-			     int            *caret_array /* OUT */)
+hb_ot_layout_get_ligature_carets (hb_font_t      *font,
+				  hb_face_t      *face,
+				  hb_direction_t  direction,
+				  hb_codepoint_t  glyph,
+				  unsigned int    start_offset,
+				  unsigned int   *caret_count /* IN/OUT */,
+				  int            *caret_array /* OUT */)
 {
   hb_ot_layout_context_t c;
   c.font = font;
   c.face = face;
-  return _get_gdef (face).get_lig_carets (&c, glyph, start_offset, caret_count, caret_array);
+  return _get_gdef (face).get_lig_carets (&c, direction, glyph, start_offset, caret_count, caret_array);
 }
 
 /*
  * GSUB/GPOS
  */
 
 static const GSUBGPOS&
 get_gsubgpos_table (hb_face_t *face,
@@ -364,17 +245,18 @@ hb_ot_layout_table_find_script (hb_face_
 
   if (g.find_script_index (script_tag, script_index))
     return TRUE;
 
   /* try finding 'DFLT' */
   if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
     return FALSE;
 
-  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
+   * including many versions of DejaVu Sans Mono! */
   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
     return FALSE;
 
   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   return FALSE;
 }
 
 hb_bool_t
@@ -589,58 +471,15 @@ hb_ot_layout_position_lookup   (hb_font_
 {
   hb_ot_layout_context_t c;
   c.font = font;
   c.face = face;
   return _get_gpos (face).position_lookup (&c, buffer, lookup_index, mask);
 }
 
 void
-hb_ot_layout_position_finish (hb_font_t    *font HB_UNUSED,
-			      hb_face_t    *face HB_UNUSED,
-			      hb_buffer_t  *buffer)
+hb_ot_layout_position_finish (hb_buffer_t  *buffer)
 {
-  unsigned int i, j;
-  unsigned int len = hb_buffer_get_length (buffer);
-  hb_internal_glyph_position_t *pos = (hb_internal_glyph_position_t *) hb_buffer_get_glyph_positions (buffer);
-
-  /* TODO: Vertical */
+  GPOS::position_finish (buffer);
+}
 
-  /* Handle cursive connections */
-  /* First handle all left-to-right connections */
-  for (j = 0; j < len; j++) {
-    if (pos[j].cursive_chain > 0)
-    {
-      pos[j].y_offset += pos[j - pos[j].cursive_chain].y_offset;
-      pos[j].cursive_chain = 0;
-    }
-  }
-  /* Then handle all right-to-left connections */
-  for (i = len; i > 0; i--) {
-    j = i - 1;
-    if (pos[j].cursive_chain < 0)
-    {
-      pos[j].y_offset += pos[j - pos[j].cursive_chain].y_offset;
-      pos[j].cursive_chain = 0;
-    }
-  }
 
-  /* Handle attachments */
-  for (i = 0; i < len; i++)
-    if (pos[i].back)
-    {
-      unsigned int back = i - pos[i].back;
-      pos[i].back = 0;
-      pos[i].x_offset += pos[back].x_offset;
-      pos[i].y_offset += pos[back].y_offset;
-
-      if (buffer->direction == HB_DIRECTION_RTL)
-	for (j = back + 1; j < i + 1; j++) {
-	  pos[i].x_offset += pos[j].x_advance;
-	  pos[i].y_offset += pos[j].y_advance;
-	}
-      else
-	for (j = back; j < i; j++) {
-	  pos[i].x_offset -= pos[j].x_advance;
-	  pos[i].y_offset -= pos[j].y_advance;
-	}
-    }
-}
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -30,70 +30,46 @@
 #include "hb-common.h"
 #include "hb-buffer.h"
 #include "hb-font.h"
 
 #include "hb-ot-tag.h"
 
 HB_BEGIN_DECLS
 
+
 #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
 #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
 #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
 
 /*
  * GDEF
  */
 
-typedef enum {
-  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED	= 0x0000,
-  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH	= 0x0002,
-  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE	= 0x0004,
-  HB_OT_LAYOUT_GLYPH_CLASS_MARK		= 0x0008,
-  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT	= 0x0010
-} hb_ot_layout_glyph_class_t;
-
-/* XXX These should eventually be removed as we move synthesized glyph
- * classes in harfbuzz. */
-
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
-hb_ot_layout_glyph_class_t
-hb_ot_layout_get_glyph_class (hb_face_t      *face,
-			      hb_codepoint_t  glyph);
-
-void
-hb_ot_layout_set_glyph_class (hb_face_t                 *face,
-			      hb_codepoint_t             glyph,
-			      hb_ot_layout_glyph_class_t klass);
-
-void
-hb_ot_layout_build_glyph_classes (hb_face_t      *face,
-				  hb_codepoint_t *glyphs,
-				  unsigned char  *klasses,
-				  uint16_t        count);
-
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
 				hb_codepoint_t  glyph,
 				unsigned int    start_offset,
 				unsigned int   *point_count /* IN/OUT */,
 				unsigned int   *point_array /* OUT */);
 
 /* Ligature caret positions */
 unsigned int
-hb_ot_layout_get_lig_carets (hb_font_t      *font,
-			     hb_face_t      *face,
-			     hb_codepoint_t  glyph,
-			     unsigned int    start_offset,
-			     unsigned int   *caret_count /* IN/OUT */,
-			     int            *caret_array /* OUT */);
+hb_ot_layout_get_ligature_carets (hb_font_t      *font,
+				  hb_face_t      *face,
+				  hb_direction_t  direction,
+				  hb_codepoint_t  glyph,
+				  unsigned int    start_offset,
+				  unsigned int   *caret_count /* IN/OUT */,
+				  int            *caret_array /* OUT */);
 
 
 /*
  * GSUB/GPOS feature query and enumeration interface
  */
 
 #define HB_OT_LAYOUT_NO_SCRIPT_INDEX		((unsigned int) 0xFFFF)
 #define HB_OT_LAYOUT_NO_FEATURE_INDEX		((unsigned int) 0xFFFF)
@@ -207,16 +183,14 @@ hb_bool_t
 hb_ot_layout_position_lookup (hb_font_t    *font,
 			      hb_face_t    *face,
 			      hb_buffer_t  *buffer,
 			      unsigned int  lookup_index,
 			      hb_mask_t     mask);
 
 /* Should be called after all the position_lookup's are done */
 void
-hb_ot_layout_position_finish (hb_font_t    *font,
-			      hb_face_t    *face,
-			      hb_buffer_t  *buffer);
+hb_ot_layout_position_finish (hb_buffer_t  *buffer);
 
 
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_MAP_PRIVATE_HH
+#define HB_OT_MAP_PRIVATE_HH
+
+#include "hb-buffer-private.hh"
+
+#include "hb-ot-layout.h"
+
+HB_BEGIN_DECLS
+
+
+#define MAX_FEATURES 100 /* FIXME */
+#define MAX_LOOKUPS 1000 /* FIXME */
+
+static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
+
+struct hb_ot_map_t {
+
+  private:
+
+  struct feature_info_t {
+    hb_tag_t tag;
+    unsigned int seq; /* sequence#, used for stable sorting only */
+    unsigned int max_value;
+    bool global; /* whether the feature applies value to every glyph in the buffer */
+    unsigned int default_value; /* for non-global features, what should the unset glyphs take */
+
+    static int cmp (const feature_info_t *a, const feature_info_t *b)
+    { return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
+  };
+
+  struct feature_map_t {
+    hb_tag_t tag; /* should be first for our bsearch to work */
+    unsigned int index[2]; /* GSUB, GPOS */
+    unsigned int shift;
+    hb_mask_t mask;
+    hb_mask_t _1_mask; /* mask for value=1, for quick access */
+
+    static int cmp (const feature_map_t *a, const feature_map_t *b)
+    { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
+  };
+
+  struct lookup_map_t {
+    unsigned int index;
+    hb_mask_t mask;
+
+    static int cmp (const lookup_map_t *a, const lookup_map_t *b)
+    { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
+  };
+
+  HB_INTERNAL void add_lookups (hb_face_t    *face,
+				unsigned int  table_index,
+				unsigned int  feature_index,
+				hb_mask_t     mask);
+
+
+  public:
+
+  hb_ot_map_t (void) : feature_count (0) {}
+
+  void add_feature (hb_tag_t tag, unsigned int value, bool global)
+  {
+    feature_info_t *info = &feature_infos[feature_count++];
+    info->tag = tag;
+    info->seq = feature_count;
+    info->max_value = value;
+    info->global = global;
+    info->default_value = global ? value : 0;
+  }
+
+  inline void add_bool_feature (hb_tag_t tag, bool global = true)
+  { add_feature (tag, 1, global); }
+
+  HB_INTERNAL void compile (hb_face_t *face,
+			    const hb_segment_properties_t *props);
+
+  inline hb_mask_t get_global_mask (void) const { return global_mask; }
+
+  inline hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift = NULL) const {
+    const feature_map_t *map = (const feature_map_t *) bsearch (&tag, feature_maps, feature_count, sizeof (feature_maps[0]), (hb_compare_func_t) feature_map_t::cmp);
+    if (shift) *shift = map ? map->shift : 0;
+    return map ? map->mask : 0;
+  }
+
+  inline hb_mask_t get_1_mask (hb_tag_t tag) const {
+    const feature_map_t *map = (const feature_map_t *) bsearch (&tag, feature_maps, feature_count, sizeof (feature_maps[0]), (hb_compare_func_t) feature_map_t::cmp);
+    return map ? map->_1_mask : 0;
+  }
+
+  inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const {
+    for (unsigned int i = 0; i < lookup_count[0]; i++)
+      hb_ot_layout_substitute_lookup (face, buffer, lookup_maps[0][i].index, lookup_maps[0][i].mask);
+  }
+
+  inline void position (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer) const {
+    for (unsigned int i = 0; i < lookup_count[1]; i++)
+      hb_ot_layout_position_lookup (font, face, buffer, lookup_maps[1][i].index, lookup_maps[1][i].mask);
+  }
+
+  private:
+
+  hb_mask_t global_mask;
+
+  unsigned int feature_count;
+  feature_info_t feature_infos[MAX_FEATURES]; /* used before compile() only */
+  feature_map_t feature_maps[MAX_FEATURES];
+
+  lookup_map_t lookup_maps[2][MAX_LOOKUPS]; /* GSUB/GPOS */
+  unsigned int lookup_count[2];
+};
+
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_MAP_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-map-private.hh"
+
+#include "hb-ot-shape-private.hh"
+
+HB_BEGIN_DECLS
+
+
+void
+hb_ot_map_t::add_lookups (hb_face_t    *face,
+			  unsigned int  table_index,
+			  unsigned int  feature_index,
+			  hb_mask_t     mask)
+{
+  unsigned int i = MAX_LOOKUPS - lookup_count[table_index];
+  lookup_map_t *lookups = lookup_maps[table_index] + lookup_count[table_index];
+
+  unsigned int *lookup_indices = (unsigned int *) lookups;
+
+  hb_ot_layout_feature_get_lookup_indexes (face,
+					   table_tags[table_index],
+					   feature_index,
+					   0, &i,
+					   lookup_indices);
+
+  lookup_count[table_index] += i;
+
+  while (i--) {
+    lookups[i].mask = mask;
+    lookups[i].index = lookup_indices[i];
+  }
+}
+
+
+void
+hb_ot_map_t::compile (hb_face_t *face,
+		      const hb_segment_properties_t *props)
+{
+ global_mask = 1;
+ lookup_count[0] = lookup_count[1] = 0;
+
+  if (!feature_count)
+    return;
+
+
+  /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
+   * features not available in either table and not waste precious bits for them. */
+
+  const hb_tag_t *script_tags;
+  hb_tag_t language_tag;
+
+  script_tags = hb_ot_tags_from_script (props->script);
+  language_tag = hb_ot_tag_from_language (props->language);
+
+  unsigned int script_index[2], language_index[2];
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    hb_tag_t table_tag = table_tags[table_index];
+    hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index]);
+    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+  }
+
+
+  /* Sort features and merge duplicates */
+  qsort (feature_infos, feature_count, sizeof (feature_infos[0]), (hb_compare_func_t) feature_info_t::cmp);
+  unsigned int j = 0;
+  for (unsigned int i = 1; i < feature_count; i++)
+    if (feature_infos[i].tag != feature_infos[j].tag)
+      feature_infos[++j] = feature_infos[i];
+    else {
+      if (feature_infos[i].global)
+	feature_infos[j] = feature_infos[i];
+      else {
+	feature_infos[j].global = false;
+	feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+	/* Inherit default_value from j */
+      }
+    }
+  feature_count = j + 1;
+
+
+  /* Allocate bits now */
+  unsigned int next_bit = 1;
+  j = 0;
+  for (unsigned int i = 0; i < feature_count; i++) {
+    const feature_info_t *info = &feature_infos[i];
+
+    unsigned int bits_needed;
+
+    if (info->global && info->max_value == 1)
+      /* Uses the global bit */
+      bits_needed = 0;
+    else
+      bits_needed = _hb_bit_storage (info->max_value);
+
+    if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
+      continue; /* Feature disabled, or not enough bits. */
+
+
+    bool found = false;
+    unsigned int feature_index[2];
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+      found |= hb_ot_layout_language_find_feature (face,
+						   table_tags[table_index],
+						   script_index[table_index],
+						   language_index[table_index],
+						   info->tag,
+						   &feature_index[table_index]);
+    if (!found)
+      continue;
+
+
+    feature_map_t *map = &feature_maps[j++];
+
+    map->tag = info->tag;
+    map->index[0] = feature_index[0];
+    map->index[1] = feature_index[1];
+    if (info->global && info->max_value == 1) {
+      /* Uses the global bit */
+      map->shift = 0;
+      map->mask = 1;
+    } else {
+      map->shift = next_bit;
+      map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
+      next_bit += bits_needed;
+      if (info->global)
+	global_mask |= (info->default_value << map->shift) & map->mask;
+    }
+    map->_1_mask = (1 << map->shift) & map->mask;
+
+  }
+  feature_count = j;
+
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    hb_tag_t table_tag = table_tags[table_index];
+
+    /* Collect lookup indices for features */
+
+    unsigned int required_feature_index;
+    if (hb_ot_layout_language_get_required_feature_index (face,
+							  table_tag,
+							  script_index[table_index],
+							  language_index[table_index],
+							  &required_feature_index))
+      add_lookups (face, table_index, required_feature_index, 1);
+
+    for (unsigned i = 0; i < feature_count; i++)
+      add_lookups (face, table_index, feature_maps[i].index[table_index], feature_maps[i].mask);
+
+    /* Sort lookups and merge duplicates */
+    qsort (lookup_maps[table_index], lookup_count[table_index], sizeof (lookup_maps[table_index][0]), (hb_compare_func_t) lookup_map_t::cmp);
+    if (lookup_count[table_index])
+    {
+      unsigned int j = 0;
+      for (unsigned int i = 1; i < lookup_count[table_index]; i++)
+	if (lookup_maps[table_index][i].index != lookup_maps[table_index][j].index)
+	  lookup_maps[table_index][++j] = lookup_maps[table_index][i];
+	else
+	  lookup_maps[table_index][j].mask |= lookup_maps[table_index][i].mask;
+      j++;
+      lookup_count[table_index] = j;
+    }
+  }
+}
+
+
+HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.h
@@ -0,0 +1,619 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ *   ./gen-arabic-joining-table.py < ArabicShaping.txt
+ *
+ * on the ArabicShaping.txt file with the header:
+ *
+ * # ArabicShaping-6.1.0.txt
+ * # Date: 2010-11-09, 12:10:00 PST [KW]
+ */
+#define JOINING_TABLE_FIRST	0x0600
+#define JOINING_TABLE_LAST	0x0858
+static const uint8_t joining_table[JOINING_TABLE_LAST-JOINING_TABLE_FIRST+2] =
+{
+  JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 0604 */
+  JOINING_TYPE_X, /* 0605 */
+  JOINING_TYPE_X, /* 0606 */
+  JOINING_TYPE_X, /* 0607 */
+  JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 0609 */
+  JOINING_TYPE_X, /* 060A */
+  JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 060C */
+  JOINING_TYPE_X, /* 060D */
+  JOINING_TYPE_X, /* 060E */
+  JOINING_TYPE_X, /* 060F */
+  JOINING_TYPE_X, /* 0610 */
+  JOINING_TYPE_X, /* 0611 */
+  JOINING_TYPE_X, /* 0612 */
+  JOINING_TYPE_X, /* 0613 */
+  JOINING_TYPE_X, /* 0614 */
+  JOINING_TYPE_X, /* 0615 */
+  JOINING_TYPE_X, /* 0616 */
+  JOINING_TYPE_X, /* 0617 */
+  JOINING_TYPE_X, /* 0618 */
+  JOINING_TYPE_X, /* 0619 */
+  JOINING_TYPE_X, /* 061A */
+  JOINING_TYPE_X, /* 061B */
+  JOINING_TYPE_X, /* 061C */
+  JOINING_TYPE_X, /* 061D */
+  JOINING_TYPE_X, /* 061E */
+  JOINING_TYPE_X, /* 061F */
+  JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */
+  JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
+  JOINING_TYPE_R, /* 0622; MADDA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0623; HAMZA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0624; HAMZA ON WAW; R; WAW */
+  JOINING_TYPE_R, /* 0625; HAMZA UNDER ALEF; R; ALEF */
+  JOINING_TYPE_D, /* 0626; HAMZA ON YEH; D; YEH */
+  JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */
+  JOINING_TYPE_D, /* 0628; BEH; D; BEH */
+  JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */
+  JOINING_TYPE_D, /* 062A; TEH; D; BEH */
+  JOINING_TYPE_D, /* 062B; THEH; D; BEH */
+  JOINING_TYPE_D, /* 062C; JEEM; D; HAH */
+  JOINING_TYPE_D, /* 062D; HAH; D; HAH */
+  JOINING_TYPE_D, /* 062E; KHAH; D; HAH */
+  JOINING_TYPE_R, /* 062F; DAL; R; DAL */
+  JOINING_TYPE_R, /* 0630; THAL; R; DAL */
+  JOINING_TYPE_R, /* 0631; REH; R; REH */
+  JOINING_TYPE_R, /* 0632; ZAIN; R; REH */
+  JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */
+  JOINING_TYPE_D, /* 0634; SHEEN; D; SEEN */
+  JOINING_TYPE_D, /* 0635; SAD; D; SAD */
+  JOINING_TYPE_D, /* 0636; DAD; D; SAD */
+  JOINING_TYPE_D, /* 0637; TAH; D; TAH */
+  JOINING_TYPE_D, /* 0638; ZAH; D; TAH */
+  JOINING_TYPE_D, /* 0639; AIN; D; AIN */
+  JOINING_TYPE_D, /* 063A; GHAIN; D; AIN */
+  JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V; D; FARSI YEH */
+  JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */
+  JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */
+  JOINING_TYPE_D, /* 0641; FEH; D; FEH */
+  JOINING_TYPE_D, /* 0642; QAF; D; QAF */
+  JOINING_TYPE_D, /* 0643; KAF; D; KAF */
+  JOINING_TYPE_D, /* 0644; LAM; D; LAM */
+  JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */
+  JOINING_TYPE_D, /* 0646; NOON; D; NOON */
+  JOINING_TYPE_D, /* 0647; HEH; D; HEH */
+  JOINING_TYPE_R, /* 0648; WAW; R; WAW */
+  JOINING_TYPE_D, /* 0649; ALEF MAKSURA; D; YEH */
+  JOINING_TYPE_D, /* 064A; YEH; D; YEH */
+  JOINING_TYPE_X, /* 064B */
+  JOINING_TYPE_X, /* 064C */
+  JOINING_TYPE_X, /* 064D */
+  JOINING_TYPE_X, /* 064E */
+  JOINING_TYPE_X, /* 064F */
+  JOINING_TYPE_X, /* 0650 */
+  JOINING_TYPE_X, /* 0651 */
+  JOINING_TYPE_X, /* 0652 */
+  JOINING_TYPE_X, /* 0653 */
+  JOINING_TYPE_X, /* 0654 */
+  JOINING_TYPE_X, /* 0655 */
+  JOINING_TYPE_X, /* 0656 */
+  JOINING_TYPE_X, /* 0657 */
+  JOINING_TYPE_X, /* 0658 */
+  JOINING_TYPE_X, /* 0659 */
+  JOINING_TYPE_X, /* 065A */
+  JOINING_TYPE_X, /* 065B */
+  JOINING_TYPE_X, /* 065C */
+  JOINING_TYPE_X, /* 065D */
+  JOINING_TYPE_X, /* 065E */
+  JOINING_TYPE_X, /* 065F */
+  JOINING_TYPE_X, /* 0660 */
+  JOINING_TYPE_X, /* 0661 */
+  JOINING_TYPE_X, /* 0662 */
+  JOINING_TYPE_X, /* 0663 */
+  JOINING_TYPE_X, /* 0664 */
+  JOINING_TYPE_X, /* 0665 */
+  JOINING_TYPE_X, /* 0666 */
+  JOINING_TYPE_X, /* 0667 */
+  JOINING_TYPE_X, /* 0668 */
+  JOINING_TYPE_X, /* 0669 */
+  JOINING_TYPE_X, /* 066A */
+  JOINING_TYPE_X, /* 066B */
+  JOINING_TYPE_X, /* 066C */
+  JOINING_TYPE_X, /* 066D */
+  JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */
+  JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */
+  JOINING_TYPE_X, /* 0670 */
+  JOINING_TYPE_R, /* 0671; HAMZAT WASL ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0672; WAVY HAMZA ON ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0673; WAVY HAMZA UNDER ALEF; R; ALEF */
+  JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */
+  JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */
+  JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */
+  JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA; R; WAW */
+  JOINING_TYPE_D, /* 0678; HIGH HAMZA YEH; D; YEH */
+  JOINING_TYPE_D, /* 0679; TEH WITH SMALL TAH; D; BEH */
+  JOINING_TYPE_D, /* 067A; TEH WITH 2 DOTS VERTICAL ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 067B; BEH WITH 2 DOTS VERTICAL BELOW; D; BEH */
+  JOINING_TYPE_D, /* 067C; TEH WITH RING; D; BEH */
+  JOINING_TYPE_D, /* 067D; TEH WITH 3 DOTS ABOVE DOWNWARD; D; BEH */
+  JOINING_TYPE_D, /* 067E; TEH WITH 3 DOTS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 067F; TEH WITH 4 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0680; BEH WITH 4 DOTS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0681; HAMZA ON HAH; D; HAH */
+  JOINING_TYPE_D, /* 0682; HAH WITH 2 DOTS VERTICAL ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0683; HAH WITH MIDDLE 2 DOTS; D; HAH */
+  JOINING_TYPE_D, /* 0684; HAH WITH MIDDLE 2 DOTS VERTICAL; D; HAH */
+  JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0686; HAH WITH MIDDLE 3 DOTS DOWNWARD; D; HAH */
+  JOINING_TYPE_D, /* 0687; HAH WITH MIDDLE 4 DOTS; D; HAH */
+  JOINING_TYPE_R, /* 0688; DAL WITH SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 0689; DAL WITH RING; R; DAL */
+  JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */
+  JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */
+  JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 068F; DAL WITH 3 DOTS ABOVE DOWNWARD; R; DAL */
+  JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */
+  JOINING_TYPE_R, /* 0691; REH WITH SMALL TAH; R; REH */
+  JOINING_TYPE_R, /* 0692; REH WITH SMALL V; R; REH */
+  JOINING_TYPE_R, /* 0693; REH WITH RING; R; REH */
+  JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */
+  JOINING_TYPE_R, /* 0695; REH WITH SMALL V BELOW; R; REH */
+  JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */
+  JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */
+  JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */
+  JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */
+  JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */
+  JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */
+  JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */
+  JOINING_TYPE_D, /* 06A2; FEH WITH DOT MOVED BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A4; FEH WITH 3 DOTS ABOVE; D; FEH */
+  JOINING_TYPE_D, /* 06A5; FEH WITH 3 DOTS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 06A6; FEH WITH 4 DOTS ABOVE; D; FEH */
+  JOINING_TYPE_D, /* 06A7; QAF WITH DOT ABOVE; D; QAF */
+  JOINING_TYPE_D, /* 06A8; QAF WITH 3 DOTS ABOVE; D; QAF */
+  JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */
+  JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */
+  JOINING_TYPE_D, /* 06AB; KAF WITH RING; D; GAF */
+  JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */
+  JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */
+  JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */
+  JOINING_TYPE_D, /* 06AF; GAF; D; GAF */
+  JOINING_TYPE_D, /* 06B0; GAF WITH RING; D; GAF */
+  JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 06B3; GAF WITH 2 DOTS VERTICAL BELOW; D; GAF */
+  JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 06B5; LAM WITH SMALL V; D; LAM */
+  JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */
+  JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */
+  JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */
+  JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */
+  JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */
+  JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH SMALL TAH; D; NOON */
+  JOINING_TYPE_D, /* 06BC; NOON WITH RING; D; NOON */
+  JOINING_TYPE_D, /* 06BD; NYA; D; NYA */
+  JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */
+  JOINING_TYPE_D, /* 06BF; HAH WITH MIDDLE 3 DOTS DOWNWARD AND DOT ABOVE; D; HAH */
+  JOINING_TYPE_R, /* 06C0; HAMZA ON HEH; R; TEH MARBUTA */
+  JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
+  JOINING_TYPE_D, /* 06C2; HAMZA ON HEH GOAL; D; HEH GOAL */
+  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
+  JOINING_TYPE_R, /* 06C4; WAW WITH RING; R; WAW */
+  JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
+  JOINING_TYPE_R, /* 06C6; WAW WITH SMALL V; R; WAW */
+  JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA; R; WAW */
+  JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED SMALL V; R; WAW */
+  JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */
+  JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */
+  JOINING_TYPE_D, /* 06CE; FARSI YEH WITH SMALL V; D; FARSI YEH */
+  JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 06D0; YEH WITH 2 DOTS VERTICAL BELOW; D; YEH */
+  JOINING_TYPE_D, /* 06D1; YEH WITH 3 DOTS BELOW; D; YEH */
+  JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */
+  JOINING_TYPE_R, /* 06D3; HAMZA ON YEH BARREE; R; YEH BARREE */
+  JOINING_TYPE_X, /* 06D4 */
+  JOINING_TYPE_R, /* 06D5; AE; R; TEH MARBUTA */
+  JOINING_TYPE_X, /* 06D6 */
+  JOINING_TYPE_X, /* 06D7 */
+  JOINING_TYPE_X, /* 06D8 */
+  JOINING_TYPE_X, /* 06D9 */
+  JOINING_TYPE_X, /* 06DA */
+  JOINING_TYPE_X, /* 06DB */
+  JOINING_TYPE_X, /* 06DC */
+  JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */
+  JOINING_TYPE_X, /* 06DE */
+  JOINING_TYPE_X, /* 06DF */
+  JOINING_TYPE_X, /* 06E0 */
+  JOINING_TYPE_X, /* 06E1 */
+  JOINING_TYPE_X, /* 06E2 */
+  JOINING_TYPE_X, /* 06E3 */
+  JOINING_TYPE_X, /* 06E4 */
+  JOINING_TYPE_X, /* 06E5 */
+  JOINING_TYPE_X, /* 06E6 */
+  JOINING_TYPE_X, /* 06E7 */
+  JOINING_TYPE_X, /* 06E8 */
+  JOINING_TYPE_X, /* 06E9 */
+  JOINING_TYPE_X, /* 06EA */
+  JOINING_TYPE_X, /* 06EB */
+  JOINING_TYPE_X, /* 06EC */
+  JOINING_TYPE_X, /* 06ED */
+  JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V; R; DAL */
+  JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V; R; REH */
+  JOINING_TYPE_X, /* 06F0 */
+  JOINING_TYPE_X, /* 06F1 */
+  JOINING_TYPE_X, /* 06F2 */
+  JOINING_TYPE_X, /* 06F3 */
+  JOINING_TYPE_X, /* 06F4 */
+  JOINING_TYPE_X, /* 06F5 */
+  JOINING_TYPE_X, /* 06F6 */
+  JOINING_TYPE_X, /* 06F7 */
+  JOINING_TYPE_X, /* 06F8 */
+  JOINING_TYPE_X, /* 06F9 */
+  JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 06FB; DAD WITH DOT BELOW; D; SAD */
+  JOINING_TYPE_D, /* 06FC; GHAIN WITH DOT BELOW; D; AIN */
+  JOINING_TYPE_X, /* 06FD */
+  JOINING_TYPE_X, /* 06FE */
+  JOINING_TYPE_D, /* 06FF; HEH WITH INVERTED V; D; KNOTTED HEH */
+  JOINING_TYPE_X, /* 0700 */
+  JOINING_TYPE_X, /* 0701 */
+  JOINING_TYPE_X, /* 0702 */
+  JOINING_TYPE_X, /* 0703 */
+  JOINING_TYPE_X, /* 0704 */
+  JOINING_TYPE_X, /* 0705 */
+  JOINING_TYPE_X, /* 0706 */
+  JOINING_TYPE_X, /* 0707 */
+  JOINING_TYPE_X, /* 0708 */
+  JOINING_TYPE_X, /* 0709 */
+  JOINING_TYPE_X, /* 070A */
+  JOINING_TYPE_X, /* 070B */
+  JOINING_TYPE_X, /* 070C */
+  JOINING_TYPE_X, /* 070D */
+  JOINING_TYPE_X, /* 070E */
+  JOINING_TYPE_X, /* 070F */
+  JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */
+  JOINING_TYPE_X, /* 0711 */
+  JOINING_TYPE_D, /* 0712; BETH; D; BETH */
+  JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */
+  JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */
+  JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */
+  JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */
+  JOINING_TYPE_R, /* 0717; HE; R; HE */
+  JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */
+  JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */
+  JOINING_TYPE_D, /* 071A; HETH; D; HETH */
+  JOINING_TYPE_D, /* 071B; TETH; D; TETH */
+  JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */
+  JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */
+  JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */
+  JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */
+  JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */
+  JOINING_TYPE_D, /* 0721; MIM; D; MIM */
+  JOINING_TYPE_D, /* 0722; NUN; D; NUN */
+  JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */
+  JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */
+  JOINING_TYPE_D, /* 0725; E; D; E */
+  JOINING_TYPE_D, /* 0726; PE; D; PE */
+  JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */
+  JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */
+  JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */
+  JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */
+  JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */
+  JOINING_TYPE_R, /* 072C; TAW; R; TAW */
+  JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */
+  JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */
+  JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */
+  JOINING_TYPE_X, /* 0730 */
+  JOINING_TYPE_X, /* 0731 */
+  JOINING_TYPE_X, /* 0732 */
+  JOINING_TYPE_X, /* 0733 */
+  JOINING_TYPE_X, /* 0734 */
+  JOINING_TYPE_X, /* 0735 */
+  JOINING_TYPE_X, /* 0736 */
+  JOINING_TYPE_X, /* 0737 */
+  JOINING_TYPE_X, /* 0738 */
+  JOINING_TYPE_X, /* 0739 */
+  JOINING_TYPE_X, /* 073A */
+  JOINING_TYPE_X, /* 073B */
+  JOINING_TYPE_X, /* 073C */
+  JOINING_TYPE_X, /* 073D */
+  JOINING_TYPE_X, /* 073E */
+  JOINING_TYPE_X, /* 073F */
+  JOINING_TYPE_X, /* 0740 */
+  JOINING_TYPE_X, /* 0741 */
+  JOINING_TYPE_X, /* 0742 */
+  JOINING_TYPE_X, /* 0743 */
+  JOINING_TYPE_X, /* 0744 */
+  JOINING_TYPE_X, /* 0745 */
+  JOINING_TYPE_X, /* 0746 */
+  JOINING_TYPE_X, /* 0747 */
+  JOINING_TYPE_X, /* 0748 */
+  JOINING_TYPE_X, /* 0749 */
+  JOINING_TYPE_X, /* 074A */
+  JOINING_TYPE_X, /* 074B */
+  JOINING_TYPE_X, /* 074C */
+  JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */
+  JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */
+  JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */
+  JOINING_TYPE_D, /* 0750; BEH WITH 3 DOTS HORIZONTALLY BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0751; BEH WITH DOT BELOW AND 3 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0752; BEH WITH 3 DOTS POINTING UPWARDS BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0753; BEH WITH 3 DOTS POINTING UPWARDS BELOW AND 2 DOTS ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0754; BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */
+  JOINING_TYPE_D, /* 0755; BEH WITH INVERTED SMALL V BELOW; D; BEH */
+  JOINING_TYPE_D, /* 0756; BEH WITH SMALL V; D; BEH */
+  JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */
+  JOINING_TYPE_D, /* 0758; HAH WITH 3 DOTS POINTING UPWARDS BELOW; D; HAH */
+  JOINING_TYPE_R, /* 0759; DAL WITH 2 DOTS VERTICALLY BELOW AND SMALL TAH; R; DAL */
+  JOINING_TYPE_R, /* 075A; DAL WITH INVERTED SMALL V BELOW; R; DAL */
+  JOINING_TYPE_R, /* 075B; REH WITH STROKE; R; REH */
+  JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 075E; AIN WITH 3 DOTS POINTING DOWNWARDS ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 075F; AIN WITH 2 DOTS VERTICALLY ABOVE; D; AIN */
+  JOINING_TYPE_D, /* 0760; FEH WITH 2 DOTS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 0761; FEH WITH 3 DOTS POINTING UPWARDS BELOW; D; FEH */
+  JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */
+  JOINING_TYPE_D, /* 0764; KEHEH WITH 3 DOTS POINTING UPWARDS BELOW; D; GAF */
+  JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */
+  JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */
+  JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */
+  JOINING_TYPE_D, /* 0768; NOON WITH SMALL TAH; D; NOON */
+  JOINING_TYPE_D, /* 0769; NOON WITH SMALL V; D; NOON */
+  JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */
+  JOINING_TYPE_R, /* 076B; REH WITH 2 DOTS VERTICALLY ABOVE; R; REH */
+  JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */
+  JOINING_TYPE_D, /* 076D; SEEN WITH 2 DOTS VERTICALLY ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 076E; HAH WITH SMALL TAH BELOW; D; HAH */
+  JOINING_TYPE_D, /* 076F; HAH WITH SMALL TAH AND 2 DOTS; D; HAH */
+  JOINING_TYPE_D, /* 0770; SEEN WITH SMALL TAH AND 2 DOTS; D; SEEN */
+  JOINING_TYPE_R, /* 0771; REH WITH SMALL TAH AND 2 DOTS; R; REH */
+  JOINING_TYPE_D, /* 0772; HAH WITH SMALL TAH ABOVE; D; HAH */
+  JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */
+  JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */
+  JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */
+  JOINING_TYPE_D, /* 0777; YEH WITH DIGIT FOUR BELOW; D; YEH */
+  JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */
+  JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */
+  JOINING_TYPE_D, /* 077A; YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */
+  JOINING_TYPE_D, /* 077B; YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */
+  JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */
+  JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */
+  JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V; D; SEEN */
+  JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */
+  JOINING_TYPE_X, /* 0780 */
+  JOINING_TYPE_X, /* 0781 */
+  JOINING_TYPE_X, /* 0782 */
+  JOINING_TYPE_X, /* 0783 */
+  JOINING_TYPE_X, /* 0784 */
+  JOINING_TYPE_X, /* 0785 */
+  JOINING_TYPE_X, /* 0786 */
+  JOINING_TYPE_X, /* 0787 */
+  JOINING_TYPE_X, /* 0788 */
+  JOINING_TYPE_X, /* 0789 */
+  JOINING_TYPE_X, /* 078A */
+  JOINING_TYPE_X, /* 078B */
+  JOINING_TYPE_X, /* 078C */
+  JOINING_TYPE_X, /* 078D */
+  JOINING_TYPE_X, /* 078E */
+  JOINING_TYPE_X, /* 078F */
+  JOINING_TYPE_X, /* 0790 */
+  JOINING_TYPE_X, /* 0791 */
+  JOINING_TYPE_X, /* 0792 */
+  JOINING_TYPE_X, /* 0793 */
+  JOINING_TYPE_X, /* 0794 */
+  JOINING_TYPE_X, /* 0795 */
+  JOINING_TYPE_X, /* 0796 */
+  JOINING_TYPE_X, /* 0797 */
+  JOINING_TYPE_X, /* 0798 */
+  JOINING_TYPE_X, /* 0799 */
+  JOINING_TYPE_X, /* 079A */
+  JOINING_TYPE_X, /* 079B */
+  JOINING_TYPE_X, /* 079C */
+  JOINING_TYPE_X, /* 079D */
+  JOINING_TYPE_X, /* 079E */
+  JOINING_TYPE_X, /* 079F */
+  JOINING_TYPE_X, /* 07A0 */
+  JOINING_TYPE_X, /* 07A1 */
+  JOINING_TYPE_X, /* 07A2 */
+  JOINING_TYPE_X, /* 07A3 */
+  JOINING_TYPE_X, /* 07A4 */
+  JOINING_TYPE_X, /* 07A5 */
+  JOINING_TYPE_X, /* 07A6 */
+  JOINING_TYPE_X, /* 07A7 */
+  JOINING_TYPE_X, /* 07A8 */
+  JOINING_TYPE_X, /* 07A9 */
+  JOINING_TYPE_X, /* 07AA */
+  JOINING_TYPE_X, /* 07AB */
+  JOINING_TYPE_X, /* 07AC */
+  JOINING_TYPE_X, /* 07AD */
+  JOINING_TYPE_X, /* 07AE */
+  JOINING_TYPE_X, /* 07AF */
+  JOINING_TYPE_X, /* 07B0 */
+  JOINING_TYPE_X, /* 07B1 */
+  JOINING_TYPE_X, /* 07B2 */
+  JOINING_TYPE_X, /* 07B3 */
+  JOINING_TYPE_X, /* 07B4 */
+  JOINING_TYPE_X, /* 07B5 */
+  JOINING_TYPE_X, /* 07B6 */
+  JOINING_TYPE_X, /* 07B7 */
+  JOINING_TYPE_X, /* 07B8 */
+  JOINING_TYPE_X, /* 07B9 */
+  JOINING_TYPE_X, /* 07BA */
+  JOINING_TYPE_X, /* 07BB */
+  JOINING_TYPE_X, /* 07BC */
+  JOINING_TYPE_X, /* 07BD */
+  JOINING_TYPE_X, /* 07BE */
+  JOINING_TYPE_X, /* 07BF */
+  JOINING_TYPE_X, /* 07C0 */
+  JOINING_TYPE_X, /* 07C1 */
+  JOINING_TYPE_X, /* 07C2 */
+  JOINING_TYPE_X, /* 07C3 */
+  JOINING_TYPE_X, /* 07C4 */
+  JOINING_TYPE_X, /* 07C5 */
+  JOINING_TYPE_X, /* 07C6 */
+  JOINING_TYPE_X, /* 07C7 */
+  JOINING_TYPE_X, /* 07C8 */
+  JOINING_TYPE_X, /* 07C9 */
+  JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */
+  JOINING_TYPE_X, /* 07EB */
+  JOINING_TYPE_X, /* 07EC */
+  JOINING_TYPE_X, /* 07ED */
+  JOINING_TYPE_X, /* 07EE */
+  JOINING_TYPE_X, /* 07EF */
+  JOINING_TYPE_X, /* 07F0 */
+  JOINING_TYPE_X, /* 07F1 */
+  JOINING_TYPE_X, /* 07F2 */
+  JOINING_TYPE_X, /* 07F3 */
+  JOINING_TYPE_X, /* 07F4 */
+  JOINING_TYPE_X, /* 07F5 */
+  JOINING_TYPE_X, /* 07F6 */
+  JOINING_TYPE_X, /* 07F7 */
+  JOINING_TYPE_X, /* 07F8 */
+  JOINING_TYPE_X, /* 07F9 */
+  JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */
+  JOINING_TYPE_X, /* 07FB */
+  JOINING_TYPE_X, /* 07FC */
+  JOINING_TYPE_X, /* 07FD */
+  JOINING_TYPE_X, /* 07FE */
+  JOINING_TYPE_X, /* 07FF */
+  JOINING_TYPE_X, /* 0800 */
+  JOINING_TYPE_X, /* 0801 */
+  JOINING_TYPE_X, /* 0802 */
+  JOINING_TYPE_X, /* 0803 */
+  JOINING_TYPE_X, /* 0804 */
+  JOINING_TYPE_X, /* 0805 */
+  JOINING_TYPE_X, /* 0806 */
+  JOINING_TYPE_X, /* 0807 */
+  JOINING_TYPE_X, /* 0808 */
+  JOINING_TYPE_X, /* 0809 */
+  JOINING_TYPE_X, /* 080A */
+  JOINING_TYPE_X, /* 080B */
+  JOINING_TYPE_X, /* 080C */
+  JOINING_TYPE_X, /* 080D */
+  JOINING_TYPE_X, /* 080E */
+  JOINING_TYPE_X, /* 080F */
+  JOINING_TYPE_X, /* 0810 */
+  JOINING_TYPE_X, /* 0811 */
+  JOINING_TYPE_X, /* 0812 */
+  JOINING_TYPE_X, /* 0813 */
+  JOINING_TYPE_X, /* 0814 */
+  JOINING_TYPE_X, /* 0815 */
+  JOINING_TYPE_X, /* 0816 */
+  JOINING_TYPE_X, /* 0817 */
+  JOINING_TYPE_X, /* 0818 */
+  JOINING_TYPE_X, /* 0819 */
+  JOINING_TYPE_X, /* 081A */
+  JOINING_TYPE_X, /* 081B */
+  JOINING_TYPE_X, /* 081C */
+  JOINING_TYPE_X, /* 081D */
+  JOINING_TYPE_X, /* 081E */
+  JOINING_TYPE_X, /* 081F */
+  JOINING_TYPE_X, /* 0820 */
+  JOINING_TYPE_X, /* 0821 */
+  JOINING_TYPE_X, /* 0822 */
+  JOINING_TYPE_X, /* 0823 */
+  JOINING_TYPE_X, /* 0824 */
+  JOINING_TYPE_X, /* 0825 */
+  JOINING_TYPE_X, /* 0826 */
+  JOINING_TYPE_X, /* 0827 */
+  JOINING_TYPE_X, /* 0828 */
+  JOINING_TYPE_X, /* 0829 */
+  JOINING_TYPE_X, /* 082A */
+  JOINING_TYPE_X, /* 082B */
+  JOINING_TYPE_X, /* 082C */
+  JOINING_TYPE_X, /* 082D */
+  JOINING_TYPE_X, /* 082E */
+  JOINING_TYPE_X, /* 082F */
+  JOINING_TYPE_X, /* 0830 */
+  JOINING_TYPE_X, /* 0831 */
+  JOINING_TYPE_X, /* 0832 */
+  JOINING_TYPE_X, /* 0833 */
+  JOINING_TYPE_X, /* 0834 */
+  JOINING_TYPE_X, /* 0835 */
+  JOINING_TYPE_X, /* 0836 */
+  JOINING_TYPE_X, /* 0837 */
+  JOINING_TYPE_X, /* 0838 */
+  JOINING_TYPE_X, /* 0839 */
+  JOINING_TYPE_X, /* 083A */
+  JOINING_TYPE_X, /* 083B */
+  JOINING_TYPE_X, /* 083C */
+  JOINING_TYPE_X, /* 083D */
+  JOINING_TYPE_X, /* 083E */
+  JOINING_TYPE_X, /* 083F */
+  JOINING_TYPE_R, /* 0840; MANDAIC HALQA; R; No_Joining_Group */
+  JOINING_TYPE_D, /* 0841; MANDAIC AB; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0842; MANDAIC AG; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0843; MANDAIC AD; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0844; MANDAIC AH; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0845; MANDAIC USHENNA; D; No_Joining_Group */
+  JOINING_TYPE_R, /* 0846; MANDAIC AZ; R; No_Joining_Group */
+  JOINING_TYPE_D, /* 0847; MANDAIC IT; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0848; MANDAIC ATT; D; No_Joining_Group */
+  JOINING_TYPE_R, /* 0849; MANDAIC AKSA; R; No_Joining_Group */
+  JOINING_TYPE_D, /* 084A; MANDAIC AK; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 084B; MANDAIC AL; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 084C; MANDAIC AM; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 084D; MANDAIC AN; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 084E; MANDAIC AS; D; No_Joining_Group */
+  JOINING_TYPE_R, /* 084F; MANDAIC IN; R; No_Joining_Group */
+  JOINING_TYPE_D, /* 0850; MANDAIC AP; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0851; MANDAIC ASZ; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0852; MANDAIC AQ; D; No_Joining_Group */
+  JOINING_TYPE_D, /* 0853; MANDAIC AR; D; No_Joining_Group */
+  JOINING_TYPE_R, /* 0854; MANDAIC ASH; R; No_Joining_Group */
+  JOINING_TYPE_D, /* 0855; MANDAIC AT; D; No_Joining_Group */
+  JOINING_TYPE_U, /* 0856; MANDAIC DUSHENNA; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0857; MANDAIC KAD; U; No_Joining_Group */
+  JOINING_TYPE_U, /* 0858; MANDAIC AIN; U; No_Joining_Group */
+  JOINING_TYPE_X  /* dummy */
+};
+/* == End of generated table == */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+HB_BEGIN_DECLS
+
+
+/* buffer var allocations */
+#define arabic_shaping_action() var2.u32 /* arabic shaping action */
+
+
+/*
+ * Bits used in the joining tables
+ */
+enum {
+  JOINING_TYPE_U		= 0,
+  JOINING_TYPE_R		= 1,
+  JOINING_TYPE_D		= 2,
+  JOINING_TYPE_C		= JOINING_TYPE_D,
+  JOINING_GROUP_ALAPH		= 3,
+  JOINING_GROUP_DALATH_RISH	= 4,
+  NUM_STATE_MACHINE_COLS	= 5,
+
+  /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */
+
+  JOINING_TYPE_T = 6,
+  JOINING_TYPE_X = 7  /* means: use general-category to choose between U or T. */
+};
+
+/*
+ * Joining types:
+ */
+
+#include "hb-ot-shape-complex-arabic-table.h"
+
+static unsigned int get_joining_type (hb_codepoint_t u, hb_category_t gen_cat)
+{
+  /* TODO Macroize the magic bit operations */
+
+  if (likely (JOINING_TABLE_FIRST <= u && u <= JOINING_TABLE_LAST)) {
+    unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
+    if (likely (j_type != JOINING_TYPE_X))
+      return j_type;
+  }
+
+  if (unlikely ((u & ~(0x200C^0x200D)) == 0x200C)) {
+    return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
+  }
+
+  return ((1<<gen_cat) & ((1<<HB_CATEGORY_NON_SPACING_MARK)|(1<<HB_CATEGORY_ENCLOSING_MARK)|(1<<HB_CATEGORY_FORMAT))) ?
+	 JOINING_TYPE_T : JOINING_TYPE_U;
+}
+
+
+
+static const hb_tag_t arabic_syriac_features[] =
+{
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  HB_TAG('i','s','o','l'),
+  /* Syriac */
+  HB_TAG('m','e','d','2'),
+  HB_TAG('f','i','n','2'),
+  HB_TAG('f','i','n','3'),
+  HB_TAG_NONE
+};
+
+
+/* Same order as the feature array */
+enum {
+  INIT,
+  MEDI,
+  FINA,
+  ISOL,
+
+  /* Syriac */
+  MED2,
+  FIN2,
+  FIN3,
+
+  NONE,
+
+  COMMON_NUM_FEATURES = 4,
+  SYRIAC_NUM_FEATURES = 7,
+  TOTAL_NUM_FEATURES = NONE
+};
+
+static const struct arabic_state_table_entry {
+	uint8_t prev_action;
+	uint8_t curr_action;
+	uint8_t next_state;
+	uint8_t padding;
+} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
+{
+  /*   jt_U,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
+
+  /* State 0: prev was U, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
+
+  /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
+
+  /* State 2: prev was D/ISOL, willing to join. */
+  { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
+
+  /* State 3: prev was D/FINA, willing to join. */
+  { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
+
+  /* State 4: prev was FINA ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
+
+  /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
+  { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
+
+  /* State 6: prev was DALATH/RISH, not willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
+};
+
+
+
+void
+_hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb_segment_properties_t  *props)
+{
+  unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
+  for (unsigned int i = 0; i < num_features; i++)
+    plan->map.add_bool_feature (arabic_syriac_features[i], false);
+}
+
+void
+_hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c)
+{
+  unsigned int count = c->buffer->len;
+  unsigned int prev = 0, state = 0;
+
+  for (unsigned int i = 0; i < count; i++)
+  {
+    unsigned int this_type = get_joining_type (c->buffer->info[i].codepoint, (hb_category_t) c->buffer->info[i].general_category());
+
+    if (unlikely (this_type == JOINING_TYPE_T)) {
+      c->buffer->info[i].arabic_shaping_action() = NONE;
+      continue;
+    }
+
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+
+    if (entry->prev_action != NONE)
+      c->buffer->info[prev].arabic_shaping_action() = entry->prev_action;
+
+    c->buffer->info[i].arabic_shaping_action() = entry->curr_action;
+
+    prev = i;
+    state = entry->next_state;
+  }
+
+  hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
+  unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
+  for (unsigned int i = 0; i < num_masks; i++)
+    mask_array[i] = c->plan->map.get_1_mask (arabic_syriac_features[i]);
+
+  for (unsigned int i = 0; i < count; i++)
+    c->buffer->info[i].mask |= mask_array[c->buffer->info[i].arabic_shaping_action()];
+}
+
+
+HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+
+#include "hb-private.h"
+
+#include "hb-ot-shape-private.hh"
+
+HB_BEGIN_DECLS
+
+
+static inline hb_ot_complex_shaper_t
+hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
+{
+  switch ((int) props->script) {
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_NKO:
+    case HB_SCRIPT_SYRIAC:
+      return hb_ot_complex_shaper_arabic;
+
+    default:
+      return hb_ot_complex_shaper_none;
+  }
+}
+
+
+
+/*
+ * collect_features()
+ *
+ * Called during shape_plan().
+ *
+ * Shapers should use plan->map to add their features.
+ */
+
+HB_INTERNAL void _hb_ot_shape_complex_collect_features_arabic	(hb_ot_shape_plan_t *plan, const hb_segment_properties_t  *props);
+
+static inline void
+hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan,
+				      const hb_segment_properties_t  *props)
+{
+  switch (plan->shaper) {
+    case hb_ot_complex_shaper_arabic:	_hb_ot_shape_complex_collect_features_arabic (plan, props);	return;
+    case hb_ot_complex_shaper_none:	default:							return;
+  }
+}
+
+
+/* setup_masks()
+ *
+ * Called during shape_execute().
+ *
+ * Shapers should use c->plan.map to get feature masks and set on buffer.
+ */
+
+HB_INTERNAL void _hb_ot_shape_complex_setup_masks_arabic	(hb_ot_shape_context_t *c);
+
+static inline void
+hb_ot_shape_complex_setup_masks (hb_ot_shape_context_t *c)
+{
+  switch (c->plan->shaper) {
+    case hb_ot_complex_shaper_arabic:	_hb_ot_shape_complex_setup_masks_arabic (c);	return;
+    case hb_ot_complex_shaper_none:	default:					return;
+  }
+}
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_PRIVATE_HH
+#define HB_OT_SHAPE_PRIVATE_HH
+
+#include "hb-private.h"
+
+#include "hb-ot-shape.h"
+
+#include "hb-ot-map-private.hh"
+
+HB_BEGIN_DECLS
+
+
+/* buffer var allocations */
+#define general_category() var1.u8[0] /* unicode general_category (hb_category_t) */
+#define combining_class() var1.u8[1] /* unicode combining_class (uint8_t) */
+
+
+enum hb_ot_complex_shaper_t {
+  hb_ot_complex_shaper_none,
+  hb_ot_complex_shaper_arabic
+};
+
+
+struct hb_ot_shape_plan_t
+{
+  hb_ot_map_t map;
+  hb_ot_complex_shaper_t shaper;
+};
+
+
+struct hb_ot_shape_context_t
+{
+  /* Input to hb_ot_shape_execute() */
+  hb_ot_shape_plan_t *plan;
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t  *buffer;
+  const hb_feature_t *user_features;
+  unsigned int        num_user_features;
+
+  /* Transient stuff */
+  hb_direction_t original_direction;
+  hb_bool_t applied_substitute_complex;
+  hb_bool_t applied_position_complex;
+};
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -1,10 +1,11 @@
 /*
  * Copyright (C) 2009,2010  Red Hat, Inc.
+ * Copyright (C) 2010  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -17,627 +18,365 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-ot-shape.h"
-
-#include "hb-buffer-private.hh"
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 
-#include "hb-open-type-private.hh"
+HB_BEGIN_DECLS
 
-#include "hb-ot-layout.h"
 
 /* XXX vertical */
 hb_tag_t default_features[] = {
   HB_TAG('c','a','l','t'),
   HB_TAG('c','c','m','p'),
   HB_TAG('c','l','i','g'),
   HB_TAG('c','s','w','h'),
   HB_TAG('c','u','r','s'),
   HB_TAG('k','e','r','n'),
   HB_TAG('l','i','g','a'),
   HB_TAG('l','o','c','l'),
   HB_TAG('m','a','r','k'),
   HB_TAG('m','k','m','k'),
   HB_TAG('r','l','i','g')
 };
 
-enum {
-  MASK_ALWAYS_ON = 1 << 0,
-  MASK_RTLM      = 1 << 1
-};
-#define MASK_BITS_USED 2
-
-struct lookup_map {
-  unsigned int index;
-  hb_mask_t mask;
-};
-
-
 static void
-add_feature (hb_face_t    *face,
-	     hb_tag_t      table_tag,
-	     unsigned int  feature_index,
-	     hb_mask_t     mask,
-	     lookup_map   *lookups,
-	     unsigned int *num_lookups,
-	     unsigned int  room_lookups)
-{
-  unsigned int i = room_lookups - *num_lookups;
-  lookups += *num_lookups;
-
-  unsigned int *lookup_indices = (unsigned int *) lookups;
-
-  hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
-					   &i,
-					   lookup_indices);
-
-  *num_lookups += i;
-
-  while (i--) {
-    lookups[i].mask = mask;
-    lookups[i].index = lookup_indices[i];
-  }
-}
-
-static int
-cmp_lookups (const void *p1, const void *p2)
+hb_ot_shape_collect_features (hb_ot_shape_plan_t       *plan,
+			      const hb_segment_properties_t  *props,
+			      const hb_feature_t       *user_features,
+			      unsigned int              num_user_features)
 {
-  const lookup_map *a = (const lookup_map *) p1;
-  const lookup_map *b = (const lookup_map *) p2;
-
-  return a->index - b->index;
-}
-
-
-#define MAX_FEATURES 100
-
-struct hb_mask_allocator_t {
-
-  struct feature_info_t {
-    hb_tag_t tag;
-    unsigned int value;
-    unsigned int seq;
-    bool global;
-
-    static int
-    cmp (const void *p1, const void *p2)
-    {
-      const feature_info_t *a = (const feature_info_t *) p1;
-      const feature_info_t *b = (const feature_info_t *) p2;
-
-      if (a->tag != b->tag)
-        return a->tag < b->tag ? -1 : 1;
-
-      return a->seq < b->seq ? -1 : 1;
-    }
-  };
-
-  struct feature_map_t {
-    hb_tag_t tag; /* should be first */
-    unsigned int index;
-    unsigned int shift;
-    hb_mask_t mask;
-
-    static int
-    cmp (const void *p1, const void *p2)
-    {
-      const feature_map_t *a = (const feature_map_t *) p1;
-      const feature_map_t *b = (const feature_map_t *) p2;
-
-      return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
-    }
-  };
-
-  hb_mask_allocator_t (void) : count (0) {}
-
-  void add_feature (hb_tag_t tag,
-		    unsigned int value,
-		    bool global)
-  {
-    feature_info_t *info = &infos[count++];
-    info->tag = tag;
-    info->value = value;
-    info->seq = count;
-    info->global = global;
-  }
-
-  // compile lookup list; return true if kerning handled here,
-  // false if fallback kerning should be attempted
-  bool compile (hb_face_t *face,
-		hb_tag_t table_tag,
-		unsigned int script_index,
-		unsigned int language_index)
-  {
-    bool kerning_handled = false;
-    global_mask = 0;
-    next_bit = MASK_BITS_USED;
-
-    if (!count)
-      return kerning_handled;
-
-    qsort (infos, count, sizeof (infos[0]), feature_info_t::cmp);
-
-    unsigned int j = 0;
-    for (unsigned int i = 1; i < count; i++)
-      if (infos[i].tag != infos[j].tag)
-	infos[++j] = infos[i];
-      else {
-	if (infos[i].global)
-	  infos[j] = infos[i];
-	else {
-	  infos[j].global = infos[j].global && (infos[j].value == infos[i].value);
-	  infos[j].value = MAX (infos[j].value, infos[i].value);
-	}
-      }
-    count = j + 1;
-
-    /* Allocate bits now */
-    j = 0;
-    for (unsigned int i = 0; i < count; i++) {
-      const feature_info_t *info = &infos[i];
-
-      unsigned int bits_needed;
-
-      if (info->global && info->value == 1)
-        /* Uses the global bit */
-        bits_needed = 0;
-      else
-        bits_needed = _hb_bit_storage (info->value);
-
-      if (!info->value) { /* Feature disabled. */
-        if (info->global && info->tag == HB_TAG('k','e','r','n'))
-          kerning_handled = true; /* kerning explicitly disabled, don't use fallback */
-        continue;
-      }
-
-      if (next_bit + bits_needed > 8 * sizeof (hb_mask_t))
-        continue; /* Not enough bits available, skip this feature. */
-
-      unsigned int feature_index;
-      if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
-					       info->tag, &feature_index))
-        continue;
-
-      if (info->tag == HB_TAG('k','e','r','n'))
-        kerning_handled = true; /* kern feature is present, so don't use fallback */
-
-      feature_map_t *map = &maps[j++];
-
-      map->tag = info->tag;
-      map->index = feature_index;
-      if (info->global && info->value == 1) {
-        /* Uses the global bit */
-        map->shift = 0;
-	map->mask = 1;
-      } else {
-	map->shift = next_bit;
-	map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
-	next_bit += bits_needed;
-      }
-
-      if (info->global && map->mask != 1)
-        global_mask |= map->mask;
-    }
-    count = j;
-
-    return kerning_handled;
-  }
-
-  hb_mask_t get_global_mask (void) { return global_mask; }
-  const feature_map_t *find_feature (hb_tag_t tag) const {
-    static const feature_map_t off_map = { HB_TAG_NONE, Index::NOT_FOUND_INDEX, 0, 0 };
-    const feature_map_t *map = (const feature_map_t *) bsearch (&tag, maps, count, sizeof (maps[0]), feature_map_t::cmp);
-    return map ? map : &off_map;
-  }
-
-
-  private:
-
-  unsigned int count;
-  feature_info_t infos[MAX_FEATURES];
-  feature_map_t maps[MAX_FEATURES];
-
-  hb_mask_t global_mask;
-  unsigned int next_bit;
-};
-
-static bool
-setup_lookups (hb_face_t    *face,
-	       hb_buffer_t  *buffer,
-	       hb_feature_t *features,
-	       unsigned int  num_features,
-	       hb_tag_t      table_tag,
-	       lookup_map   *lookups,
-	       unsigned int *num_lookups,
-	       hb_direction_t original_direction)
-{
-  unsigned int i, j, script_index, language_index, feature_index, room_lookups;
-
-  room_lookups = *num_lookups;
-  *num_lookups = 0;
-
-  hb_ot_layout_table_choose_script (face, table_tag,
-				    hb_ot_tags_from_script (buffer->script),
-				    &script_index);
-  hb_ot_layout_script_find_language (face, table_tag, script_index,
-				     hb_ot_tag_from_language (buffer->language),
-				     &language_index);
-
-  if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index,
-							&feature_index))
-    add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
-
-
-  hb_mask_allocator_t allocator;
-
-  switch (original_direction) {
+  switch (props->direction) {
     case HB_DIRECTION_LTR:
-      allocator.add_feature (HB_TAG ('l','t','r','a'), 1, true);
-      allocator.add_feature (HB_TAG ('l','t','r','m'), 1, true);
+      plan->map.add_bool_feature (HB_TAG ('l','t','r','a'));
+      plan->map.add_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
-      allocator.add_feature (HB_TAG ('r','t','l','a'), 1, true);
-      //allocator.add_feature (HB_TAG ('r','t','l','m'), false);
-      allocator.add_feature (HB_TAG ('r','t','l','m'), 1, true);
+      plan->map.add_bool_feature (HB_TAG ('r','t','l','a'));
+      plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
     default:
       break;
   }
 
-  for (i = 0; i < ARRAY_LENGTH (default_features); i++)
-    allocator.add_feature (default_features[i], 1, true);
-
-  /* XXX complex-shaper features go here */
-
-  for (unsigned int i = 0; i < num_features; i++) {
-    const hb_feature_t *feature = &features[i];
-    allocator.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
-  }
-
+  for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++)
+    plan->map.add_bool_feature (default_features[i]);
 
-  /* Compile features */
-  bool kerning_handled = allocator.compile (face, table_tag, script_index, language_index);
-
-
-  /* Gather lookup indices for features and set buffer masks at the same time */
-
-  const hb_mask_allocator_t::feature_map_t *map;
-
-  hb_mask_t global_mask = allocator.get_global_mask ();
-  if (global_mask)
-    buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
+  hb_ot_shape_complex_collect_features (plan, props);
 
-  switch (original_direction) {
-    case HB_DIRECTION_LTR:
-      map = allocator.find_feature (HB_TAG ('l','t','r','a'));
-      add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
-      map = allocator.find_feature (HB_TAG ('l','t','r','m'));
-      add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
-      break;
-    case HB_DIRECTION_RTL:
-      map = allocator.find_feature (HB_TAG ('r','t','l','a'));
-      add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
-      //map = allocator.find_feature (HB_TAG ('r','t','l','m'));
-      add_feature (face, table_tag, map->index, MASK_RTLM, lookups, num_lookups, room_lookups);
-      break;
-    case HB_DIRECTION_TTB:
-    case HB_DIRECTION_BTT:
-    default:
-      break;
-  }
-
-  for (i = 0; i < ARRAY_LENGTH (default_features); i++)
-  {
-    map = allocator.find_feature (default_features[i]);
-    add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
+  for (unsigned int i = 0; i < num_user_features; i++) {
+    const hb_feature_t *feature = &user_features[i];
+    plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
   }
-
-  for (i = 0; i < num_features; i++)
-  {
-    hb_feature_t *feature = &features[i];
-    map = allocator.find_feature (feature->tag);
-    add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
-    if (!(feature->start == 0 && feature->end == (unsigned int)-1))
-      buffer->set_masks (features[i].value << map->shift, map->mask, feature->start, feature->end);
-  }
-
-
-  /* Sort lookups and merge duplicates */
-
-  qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
-
-  if (*num_lookups)
-  {
-    for (i = 1, j = 0; i < *num_lookups; i++)
-      if (lookups[i].index != lookups[j].index)
-	lookups[++j] = lookups[i];
-      else
-        lookups[j].mask |= lookups[i].mask;
-    j++;
-    *num_lookups = j;
-  }
-
-  return kerning_handled;
 }
 
 
-static hb_bool_t
-hb_ot_substitute_complex (hb_font_t    *font HB_UNUSED,
-			  hb_face_t    *face,
-			  hb_buffer_t  *buffer,
-			  hb_feature_t *features,
-			  unsigned int  num_features,
-			  hb_direction_t original_direction)
+static void
+hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
-  lookup_map lookups[1000]; /* FIXME */
-  unsigned int num_lookups = ARRAY_LENGTH (lookups);
-  unsigned int i;
+  hb_mask_t global_mask = c->plan->map.get_global_mask ();
+  c->buffer->reset_masks (global_mask);
+
+  hb_ot_shape_complex_setup_masks (c); /* BUFFER: Clobbers var2 */
 
-  if (!hb_ot_layout_has_substitution (face))
-    return FALSE;
-
-  (void)setup_lookups (face, buffer, features, num_features,
-		       HB_OT_TAG_GSUB,
-		       lookups, &num_lookups,
-		       original_direction);
-
-  for (i = 0; i < num_lookups; i++)
-    hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask);
-
-  return TRUE;
+  for (unsigned int i = 0; i < c->num_user_features; i++)
+  {
+    const hb_feature_t *feature = &c->user_features[i];
+    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+      unsigned int shift;
+      hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
+      c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+    }
+  }
 }
 
-static hb_bool_t
-hb_ot_position_complex (hb_font_t    *font,
-			hb_face_t    *face,
-			hb_buffer_t  *buffer,
-			hb_feature_t *features,
-			unsigned int  num_features,
-			hb_direction_t original_direction)
+
+static void
+hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
-  lookup_map lookups[1000];
-  unsigned int num_lookups = ARRAY_LENGTH (lookups);
-  unsigned int i;
+  if (!hb_ot_layout_has_substitution (c->face))
+    return;
+
+  c->plan->map.substitute (c->face, c->buffer);
+
+  c->applied_substitute_complex = TRUE;
+  return;
+}
 
-  if (!hb_ot_layout_has_positioning (face))
-    return FALSE;
+static void
+hb_ot_position_complex (hb_ot_shape_context_t *c)
+{
+
+  if (!hb_ot_layout_has_positioning (c->face))
+    return;
 
-  bool kerning_handled = setup_lookups (face, buffer, features, num_features,
-					HB_OT_TAG_GPOS,
-					lookups, &num_lookups,
-					original_direction);
+  c->plan->map.position (c->font, c->face, c->buffer);
 
-  for (i = 0; i < num_lookups; i++)
-    hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask);
+  hb_ot_layout_position_finish (c->buffer);
 
-  hb_ot_layout_position_finish (font, face, buffer);
-
-  return kerning_handled;
+  c->applied_position_complex = TRUE;
+  return;
 }
 
 
 /* Main shaper */
 
 /* Prepare */
 
 static inline hb_bool_t
 is_variation_selector (hb_codepoint_t unicode)
 {
   return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
 		   (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
 		   (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
 }
 
 static void
-hb_form_clusters (hb_buffer_t *buffer)
+hb_set_unicode_props (hb_ot_shape_context_t *c)
 {
-  unsigned int count = buffer->len;
-  for (unsigned int i = 1; i < count; i++)
-    if (buffer->unicode->v.get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK)
-      buffer->info[i].cluster = buffer->info[i - 1].cluster;
+  hb_unicode_get_general_category_func_t get_general_category = c->buffer->unicode->v.get_general_category;
+  hb_unicode_get_combining_class_func_t get_combining_class = c->buffer->unicode->v.get_combining_class;
+  hb_glyph_info_t *info = c->buffer->info;
+
+  unsigned int count = c->buffer->len;
+  for (unsigned int i = 1; i < count; i++) {
+    info[i].general_category() = get_general_category (info[i].codepoint);
+    info[i].combining_class() = get_combining_class (info[i].codepoint);
+  }
 }
 
-static hb_direction_t
-hb_ensure_native_direction (hb_buffer_t *buffer)
+static void
+hb_form_clusters (hb_ot_shape_context_t *c)
 {
-  hb_direction_t original_direction = buffer->direction;
+  unsigned int count = c->buffer->len;
+  for (unsigned int i = 1; i < count; i++)
+    if (c->buffer->info[i].general_category() == HB_CATEGORY_NON_SPACING_MARK)
+      c->buffer->info[i].cluster = c->buffer->info[i - 1].cluster;
+}
+
+static void
+hb_ensure_native_direction (hb_ot_shape_context_t *c)
+{
+  hb_direction_t direction = c->buffer->props.direction;
 
   /* TODO vertical */
-  if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
-      original_direction != _hb_script_get_horizontal_direction (buffer->script))
+  if (HB_DIRECTION_IS_HORIZONTAL (direction) &&
+      direction != _hb_script_get_horizontal_direction (c->buffer->props.script))
   {
-    hb_buffer_reverse_clusters (buffer);
-    buffer->direction = HB_DIRECTION_REVERSE (buffer->direction);
+    hb_buffer_reverse_clusters (c->buffer);
+    c->buffer->props.direction = HB_DIRECTION_REVERSE (c->buffer->props.direction);
   }
+}
 
-  return original_direction;
+static void
+hb_reset_glyph_infos (hb_ot_shape_context_t *c)
+{
+  unsigned int count = c->buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+    c->buffer->info[i].var1.u32 = c->buffer->info[i].var2.u32 = 0;
 }
 
 
 /* Substitute */
 
 static void
-hb_mirror_chars (hb_buffer_t *buffer)
+hb_mirror_chars (hb_ot_shape_context_t *c)
 {
-  hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->v.get_mirroring;
+  hb_unicode_get_mirroring_func_t get_mirroring = c->buffer->unicode->v.get_mirroring;
 
-  if (HB_DIRECTION_IS_FORWARD (buffer->direction))
+  if (HB_DIRECTION_IS_FORWARD (c->buffer->props.direction))
     return;
 
-  unsigned int count = buffer->len;
+  hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
+
+  unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint);
-    if (likely (codepoint == buffer->info[i].codepoint))
-      buffer->info[i].mask |= MASK_RTLM;
+    hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint);
+    if (likely (codepoint == c->buffer->info[i].codepoint))
+      c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
     else
-      buffer->info[i].codepoint = codepoint;
+      c->buffer->info[i].codepoint = codepoint;
   }
 }
 
 static void
 hb_map_glyphs (hb_font_t    *font,
 	       hb_face_t    *face,
 	       hb_buffer_t  *buffer)
 {
   if (unlikely (!buffer->len))
     return;
 
   buffer->clear_output ();
   unsigned int count = buffer->len - 1;
   for (buffer->i = 0; buffer->i < count;) {
     if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))) {
-      buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint));
+      buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint));
       buffer->i++;
     } else {
-      buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
+      buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
     }
   }
   if (likely (buffer->i < buffer->len))
-    buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
+    buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
   buffer->swap ();
 }
 
 static void
-hb_substitute_default (hb_font_t    *font,
-		       hb_face_t    *face,
-		       hb_buffer_t  *buffer,
-		       hb_feature_t *features HB_UNUSED,
-		       unsigned int  num_features HB_UNUSED)
+hb_substitute_default (hb_ot_shape_context_t *c)
 {
-  hb_map_glyphs (font, face, buffer);
+  hb_map_glyphs (c->font, c->face, c->buffer);
 }
 
 static void
-hb_substitute_complex_fallback (hb_font_t    *font HB_UNUSED,
-				hb_face_t    *face HB_UNUSED,
-				hb_buffer_t  *buffer HB_UNUSED,
-				hb_feature_t *features HB_UNUSED,
-				unsigned int  num_features HB_UNUSED)
+hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
 {
   /* TODO Arabic */
 }
 
 
 /* Position */
 
 static void
-hb_position_default (hb_font_t    *font,
-		     hb_face_t    *face,
-		     hb_buffer_t  *buffer,
-		     hb_feature_t *features HB_UNUSED,
-		     unsigned int  num_features HB_UNUSED)
+hb_position_default (hb_ot_shape_context_t *c)
 {
-  hb_buffer_clear_positions (buffer);
+  hb_buffer_clear_positions (c->buffer);
 
-  unsigned int count = buffer->len;
+  unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++) {
-    hb_glyph_metrics_t metrics;
-    hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics);
-    buffer->pos[i].x_advance = metrics.x_advance;
-    buffer->pos[i].y_advance = metrics.y_advance;
+    hb_font_get_glyph_advance (c->font, c->face, c->buffer->info[i].codepoint,
+			       &c->buffer->pos[i].x_advance,
+			       &c->buffer->pos[i].y_advance);
   }
 }
 
 static void
-hb_position_complex_fallback (hb_font_t    *font HB_UNUSED,
-			      hb_face_t    *face HB_UNUSED,
-			      hb_buffer_t  *buffer HB_UNUSED,
-			      hb_feature_t *features HB_UNUSED,
-			      unsigned int  num_features HB_UNUSED)
+hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
 {
   /* TODO Mark pos */
 }
 
 static void
-hb_truetype_kern (hb_font_t    *font,
-		  hb_face_t    *face,
-		  hb_buffer_t  *buffer,
-		  hb_feature_t *features HB_UNUSED,
-		  unsigned int  num_features HB_UNUSED)
+hb_truetype_kern (hb_ot_shape_context_t *c)
 {
   /* TODO Check for kern=0 */
-  unsigned int count = buffer->len;
+  unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
     hb_position_t kern, kern1, kern2;
-    kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint);
+    kern = hb_font_get_kerning (c->font, c->face, c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint);
     kern1 = kern >> 1;
     kern2 = kern - kern1;
-    buffer->pos[i - 1].x_advance += kern1;
-    buffer->pos[i].x_advance += kern2;
-    buffer->pos[i].x_offset += kern2;
+    c->buffer->pos[i - 1].x_advance += kern1;
+    c->buffer->pos[i].x_advance += kern2;
+    c->buffer->pos[i].x_offset += kern2;
   }
 }
 
 static void
-hb_position_complex_fallback_visual (hb_font_t    *font,
-				     hb_face_t    *face,
-				     hb_buffer_t  *buffer,
-				     hb_feature_t *features,
-				     unsigned int  num_features)
+hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
 {
-  hb_truetype_kern (font, face, buffer, features, num_features);
+  hb_truetype_kern (c);
 }
 
 
 /* Do it! */
 
+static void
+hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
+{
+  /* Save the original direction, we use it later. */
+  c->original_direction = c->buffer->props.direction;
+
+  hb_reset_glyph_infos (c); /* BUFFER: Clear buffer var1 and var2 */
+
+  hb_set_unicode_props (c); /* BUFFER: Set general_category and combining_class in var1 */
+
+  hb_form_clusters (c);
+
+  hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */
+
+  /* SUBSTITUTE */
+  {
+    /* Mirroring needs to see the original direction */
+    hb_mirror_chars (c);
+
+    hb_ensure_native_direction (c);
+
+    hb_substitute_default (c);
+
+    hb_ot_substitute_complex (c);
+
+    if (!c->applied_substitute_complex)
+      hb_substitute_complex_fallback (c);
+  }
+
+  /* POSITION */
+  {
+    hb_position_default (c);
+
+    hb_ot_position_complex (c);
+
+    hb_bool_t position_fallback = !c->applied_position_complex;
+    if (position_fallback)
+      hb_position_complex_fallback (c);
+
+    if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
+      hb_buffer_reverse (c->buffer);
+
+    if (position_fallback)
+      hb_position_complex_fallback_visual (c);
+  }
+
+  c->buffer->props.direction = c->original_direction;
+}
+
+void
+hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
+			   hb_face_t                *face,
+			   const hb_segment_properties_t  *props,
+			   const hb_feature_t       *user_features,
+			   unsigned int              num_user_features)
+{
+  plan->shaper = hb_ot_shape_complex_categorize (props);
+
+  hb_ot_shape_collect_features (plan, props, user_features, num_user_features);
+
+  plan->map.compile (face, props);
+}
+
+void
+hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
+		     hb_font_t          *font,
+		     hb_face_t          *face,
+		     hb_buffer_t        *buffer,
+		     const hb_feature_t *user_features,
+		     unsigned int        num_user_features)
+{
+  hb_ot_shape_context_t c = {plan, font, face, buffer, user_features, num_user_features};
+  hb_ot_shape_execute_internal (&c);
+}
+
 void
 hb_ot_shape (hb_font_t    *font,
 	     hb_face_t    *face,
 	     hb_buffer_t  *buffer,
-	     hb_feature_t *features,
-	     unsigned int  num_features)
+	     const hb_feature_t *user_features,
+	     unsigned int        num_user_features)
 {
-  hb_direction_t original_direction;
-  hb_bool_t substitute_fallback, position_fallback;
-
-  hb_form_clusters (buffer);
-
-  /* SUBSTITUTE */
-  {
-
-    buffer->clear_masks ();
-
-    /* Mirroring needs to see the original direction */
-    hb_mirror_chars (buffer);
-
-    original_direction = hb_ensure_native_direction (buffer);
-
-    hb_substitute_default (font, face, buffer, features, num_features);
-
-    substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features, original_direction);
+  hb_ot_shape_plan_t plan;
 
-    if (substitute_fallback)
-      hb_substitute_complex_fallback (font, face, buffer, features, num_features);
-
-  }
-
-  /* POSITION */
-  {
-
-    buffer->clear_masks ();
-
-    hb_position_default (font, face, buffer, features, num_features);
+  hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_user_features);
+  hb_ot_shape_execute (&plan, font, face, buffer, user_features, num_user_features);
+}
 
-    position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction);
 
-    if (position_fallback)
-      hb_position_complex_fallback (font, face, buffer, features, num_features);
-
-    if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
-      hb_buffer_reverse (buffer);
-
-    if (position_fallback)
-      hb_position_complex_fallback_visual (font, face, buffer, features, num_features);
-  }
-
-  buffer->direction = original_direction;
-}
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-ot-shape.h
+++ b/gfx/harfbuzz/src/hb-ot-shape.h
@@ -27,18 +27,20 @@
 #ifndef HB_OT_SHAPE_H
 #define HB_OT_SHAPE_H
 
 #include "hb-shape.h"
 
 
 HB_BEGIN_DECLS
 
+
 void
-hb_ot_shape (hb_font_t    *font,
-	     hb_face_t    *face,
-	     hb_buffer_t  *buffer,
-	     hb_feature_t *features,
-	     unsigned int  num_features);
+hb_ot_shape (hb_font_t          *font,
+	     hb_face_t          *face,
+	     hb_buffer_t        *buffer,
+	     const hb_feature_t *user_features,
+	     unsigned int        num_user_features);
+
 
 HB_END_DECLS
 
-#endif /* HB_OT_SHAPE_PRIVATE_H */
+#endif /* HB_OT_SHAPE_H */
--- a/gfx/harfbuzz/src/hb-ot-tag.c
+++ b/gfx/harfbuzz/src/hb-ot-tag.c
@@ -24,16 +24,18 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.h"
 #include "hb-ot.h"
 
 #include <string.h>
 
+HB_BEGIN_DECLS
+
 
 /*
  * Complete list at:
  * http://www.microsoft.com/typography/otspec/scripttags.htm
  */
 static const hb_tag_t ot_scripts[][3] = {
   {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_COMMON */
   {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_INHERITED */
@@ -118,31 +120,36 @@ static const hb_tag_t ot_scripts[][3] = 
   {HB_TAG('c','h','a','m')},	/* HB_SCRIPT_CHAM */
   {HB_TAG('o','l','c','k')},	/* HB_SCRIPT_OL_CHIKI */
   {HB_TAG('v','a','i',' ')},	/* HB_SCRIPT_VAI */
   {HB_TAG('c','a','r','i')},	/* HB_SCRIPT_CARIAN */
   {HB_TAG('l','y','c','i')},	/* HB_SCRIPT_LYCIAN */
   {HB_TAG('l','y','d','i')},	/* HB_SCRIPT_LYDIAN */
 
   /* Unicode-5.2 additions */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_AVESTAN */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_BAMUM */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_EGYPTIAN_HIEROGLYPHS */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_IMPERIAL_ARAMAIC */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_INSCRIPTIONAL_PAHLAVI */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_INSCRIPTIONAL_PARTHIAN */
+  {HB_TAG('a','v','s','t')},	/* HB_SCRIPT_AVESTAN */
+  {HB_TAG('b','a','m','u')},	/* HB_SCRIPT_BAMUM */
+  {HB_TAG('e','g','y','p')},	/* HB_SCRIPT_EGYPTIAN_HIEROGLYPHS */
+  {HB_TAG('a','r','m','i')},	/* HB_SCRIPT_IMPERIAL_ARAMAIC */
+  {HB_TAG('p','h','l','i')},	/* HB_SCRIPT_INSCRIPTIONAL_PAHLAVI */
+  {HB_TAG('p','r','t','i')},	/* HB_SCRIPT_INSCRIPTIONAL_PARTHIAN */
   {HB_TAG('j','a','v','a')},	/* HB_SCRIPT_JAVANESE */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_KAITHI */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_LISU */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_MEITEI_MAYEK */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_OLD_SOUTH_ARABIAN */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_OLD_TURKIC */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_SAMARITAN */
-  {HB_TAG('D','F','L','T')},	/* HB_SCRIPT_TAI_THAM */
-  {HB_TAG('D','F','L','T')} 	/* HB_SCRIPT_TAI_VIET */
+  {HB_TAG('k','t','h','i')},	/* HB_SCRIPT_KAITHI */
+  {HB_TAG('l','i','s','u')},	/* HB_SCRIPT_LISU */
+  {HB_TAG('m','y','e','i')},	/* HB_SCRIPT_MEETEI_MAYEK */
+  {HB_TAG('s','a','r','b')},	/* HB_SCRIPT_OLD_SOUTH_ARABIAN */
+  {HB_TAG('o','r','k','h')},	/* HB_SCRIPT_OLD_TURKIC */
+  {HB_TAG('s','a','m','r')},	/* HB_SCRIPT_SAMARITAN */
+  {HB_TAG('l','a','n','a')},	/* HB_SCRIPT_TAI_THAM */
+  {HB_TAG('t','a','v','t')},	/* HB_SCRIPT_TAI_VIET */
+
+  /* Unicode-6.0 additions */
+  {HB_TAG('b','a','t','k')},	/* HB_SCRIPT_BATAK */
+  {HB_TAG('b','r','a','h')},	/* HB_SCRIPT_BRAHMI */
+  {HB_TAG('m','a','n','d')} 	/* HB_SCRIPT_MANDAIC */
 };
 
 const hb_tag_t *
 hb_ot_tags_from_script (hb_script_t script)
 {
   static const hb_tag_t def_tag[] = {HB_OT_TAG_DEFAULT_SCRIPT, HB_TAG_NONE};
 
   if (unlikely ((unsigned int) script >= ARRAY_LENGTH (ot_scripts)))
@@ -584,20 +591,19 @@ static const LangTag ot_languages[] = {
 /*{"??",	HB_TAG('X','B','D',' ')},*/	/* Tai Lue */
 /*{"??",	HB_TAG('Y','C','R',' ')},*/	/* Y-Cree */
 /*{"??",	HB_TAG('Y','I','C',' ')},*/	/* Yi Classic */
 /*{"??",	HB_TAG('Y','I','M',' ')},*/	/* Yi Modern */
 /*{"??",	HB_TAG('Z','H','P',' ')},*/	/* Chinese Phonetic */
 };
 
 static int
-lang_compare_first_component (const void *pa,
-			      const void *pb)
+lang_compare_first_component (const char *a,
+			      const char *b)
 {
-  const char *a = pa, *b = pb;
   unsigned int da, db;
   const char *p;
 
   p = strstr (a, "-");
   da = p ? (unsigned int) (p - a) : strlen (a);
 
   p = strstr (b, "-");
   db = p ? (unsigned int) (p - b) : strlen (b);
@@ -624,45 +630,43 @@ hb_ot_tag_from_language (hb_language_t l
     return HB_OT_TAG_DEFAULT_LANGUAGE;
 
   lang_str = hb_language_to_string (language);
 
   if (0 == strcmp (lang_str, "x-hbot")) {
     char tag[4];
     int i;
     lang_str += 6;
-    i = 0;
 #define IS_LETTER(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
 #define TO_UPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) + 'A' - 'a' : (c))
-    while (i < 4 && IS_LETTER (lang_str[i])) {
+    for (i = 0; i < 4 && IS_LETTER (lang_str[i]); i++)
       tag[i] = TO_UPPER (lang_str[i]);
-    }
-    while (i < 4)
+    for (; i < 4; i++)
       tag[i] = ' ';
     return HB_TAG_STR (tag);
   }
 
   /* find a language matching in the first component */
   lang_tag = bsearch (lang_str, ot_languages,
 		      ARRAY_LENGTH (ot_languages), sizeof (LangTag),
-		      lang_compare_first_component);
+		      (hb_compare_func_t) lang_compare_first_component);
 
   /* we now need to find the best language matching */
   if (lang_tag)
   {
     hb_bool_t found = FALSE;
 
     /* go to the final one matching in the first component */
     while (lang_tag + 1 < ot_languages + ARRAY_LENGTH (ot_languages) &&
-	   lang_compare_first_component (lang_str, lang_tag + 1) == 0)
+	   lang_compare_first_component (lang_str, (lang_tag + 1)->language) == 0)
       lang_tag++;
 
     /* go back, find which one matches completely */
     while (lang_tag >= ot_languages &&
-	   lang_compare_first_component (lang_str, lang_tag) == 0)
+	   lang_compare_first_component (lang_str, lang_tag->language) == 0)
     {
       if (lang_matches (lang_str, lang_tag->language)) {
 	found = TRUE;
 	break;
       }
 
       lang_tag--;
     }
@@ -689,8 +693,11 @@ hb_ot_tag_to_language (hb_tag_t tag)
 
   buf[6] = tag >> 24;
   buf[7] = (tag >> 16) & 0xFF;
   buf[8] = (tag >> 8) & 0xFF;
   buf[9] = tag & 0xFF;
   buf[10] = '\0';
   return hb_language_from_string ((char *) buf);
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-ot-tag.h
+++ b/gfx/harfbuzz/src/hb-ot-tag.h
@@ -27,26 +27,28 @@
 #ifndef HB_OT_TAG_H
 #define HB_OT_TAG_H
 
 #include "hb-common.h"
 #include "hb-language.h"
 
 HB_BEGIN_DECLS
 
+
 #define HB_OT_TAG_DEFAULT_SCRIPT	HB_TAG ('D', 'F', 'L', 'T')
 #define HB_OT_TAG_DEFAULT_LANGUAGE	HB_TAG ('d', 'f', 'l', 't')
 
 const hb_tag_t *
 hb_ot_tags_from_script (hb_script_t script);
 
 hb_script_t
 hb_ot_tag_to_script (hb_tag_t tag);
 
 hb_tag_t
 hb_ot_tag_from_language (hb_language_t language);
 
 hb_language_t
 hb_ot_tag_to_language (hb_tag_t tag);
 
+
 HB_END_DECLS
 
 #endif /* HB_OT_TAG_H */
--- a/gfx/harfbuzz/src/hb-ot.h
+++ b/gfx/harfbuzz/src/hb-ot.h
@@ -28,9 +28,12 @@
 #define HB_OT_H
 
 #include "hb.h"
 
 #include "hb-ot-layout.h"
 #include "hb-ot-shape.h"
 #include "hb-ot-tag.h"
 
+HB_BEGIN_DECLS
+HB_END_DECLS
+
 #endif /* HB_OT_H */
--- a/gfx/harfbuzz/src/hb-private.h
+++ b/gfx/harfbuzz/src/hb-private.h
@@ -39,16 +39,18 @@
 
 /* We only use these two for debug output.  However, the debug code is
  * always seen by the compiler (and optimized out in non-debug builds.
  * If including these becomes a problem, we can start thinking about
  * someway around that. */
 #include <stdio.h>
 #include <errno.h>
 
+HB_BEGIN_DECLS
+
 
 /* Essentials */
 
 #ifndef NULL
 # define NULL ((void *) 0)
 #endif
 
 #undef FALSE
@@ -179,16 +181,20 @@ static inline HB_CONST_FUNC unsigned int
   while (!(number & 1)) {
     n_bits++;
     number >>= 1;
   }
   return n_bits;
 #endif
 }
 
+/* Type of bsearch() / qsort() compare function */
+typedef int (*hb_compare_func_t) (const void *, const void *);
+
+
 /* We need external help for these */
 
 #ifdef HAVE_GLIB
 
 #include <glib.h>
 
 typedef int hb_atomic_int_t;
 #define hb_atomic_int_fetch_and_add(AI, V)	g_atomic_int_exchange_and_add (&(AI), V)
@@ -246,17 +252,19 @@ typedef int hb_mutex_t;
 
 static inline hb_bool_t /* always returns TRUE */
 _hb_trace (const char *what,
 	   const char *function,
 	   const void *obj,
 	   unsigned int depth,
 	   unsigned int max_depth)
 {
-  if (depth < max_depth)
-    fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function);
+  (void) ((depth < max_depth) && fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function));
   return TRUE;
 }
 
 
 #include "hb-object-private.h"
 
+
+HB_END_DECLS
+
 #endif /* HB_PRIVATE_H */
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -31,16 +31,18 @@
 #include "hb-buffer-private.hh"
 
 #include "hb-ot-shape.h"
 
 #ifdef HAVE_GRAPHITE
 #include "hb-graphite.h"
 #endif
 
+HB_BEGIN_DECLS
+
 
 void
 hb_shape (hb_font_t    *font,
 	  hb_face_t    *face,
 	  hb_buffer_t  *buffer,
 	  hb_feature_t *features,
 	  unsigned int  num_features)
 {
@@ -53,8 +55,11 @@ hb_shape (hb_font_t    *font,
     hb_blob_destroy(silf_blob);
     return;
   }
   hb_blob_destroy(silf_blob);
 #endif
 
   hb_ot_shape (font, face, buffer, features, num_features);
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-shape.h
+++ b/gfx/harfbuzz/src/hb-shape.h
@@ -28,16 +28,17 @@
 #define HB_SHAPE_H
 
 #include "hb-common.h"
 #include "hb-buffer.h"
 #include "hb-font.h"
 
 HB_BEGIN_DECLS
 
+
 typedef struct _hb_feature_t {
   hb_tag_t      tag;
   uint32_t      value;
   unsigned int  start;
   unsigned int  end;
 } hb_feature_t;
 
 void
--- a/gfx/harfbuzz/src/hb-unicode-private.h
+++ b/gfx/harfbuzz/src/hb-unicode-private.h
@@ -28,16 +28,17 @@
 #define HB_UNICODE_PRIVATE_H
 
 #include "hb-private.h"
 
 #include "hb-unicode.h"
 
 HB_BEGIN_DECLS
 
+
 /*
  * hb_unicode_funcs_t
  */
 
 struct _hb_unicode_funcs_t {
   hb_reference_count_t ref_count;
 
   hb_bool_t immutable;
--- a/gfx/harfbuzz/src/hb-unicode.c
+++ b/gfx/harfbuzz/src/hb-unicode.c
@@ -23,16 +23,19 @@
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.h"
 
 #include "hb-unicode-private.h"
 
+HB_BEGIN_DECLS
+
+
 /*
  * hb_unicode_funcs_t
  */
 
 static hb_codepoint_t hb_unicode_get_mirroring_nil (hb_codepoint_t unicode) { return unicode; }
 static hb_category_t hb_unicode_get_general_category_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_CATEGORY_OTHER_LETTER; }
 static hb_script_t hb_unicode_get_script_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_SCRIPT_UNKNOWN; }
 static unsigned int hb_unicode_get_combining_class_nil (hb_codepoint_t unicode HB_UNUSED) { return 0; }
@@ -100,16 +103,22 @@ void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
 {
   if (HB_OBJECT_IS_INERT (ufuncs))
     return;
 
   ufuncs->immutable = TRUE;
 }
 
+hb_bool_t
+hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->immutable;
+}
+
 
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
 				     hb_unicode_get_mirroring_func_t mirroring_func)
 {
   if (ufuncs->immutable)
     return;
 
@@ -152,16 +161,48 @@ hb_unicode_funcs_set_eastasian_width_fun
 {
   if (ufuncs->immutable)
     return;
 
   ufuncs->v.get_eastasian_width = eastasian_width_func ? eastasian_width_func : hb_unicode_get_eastasian_width_nil;
 }
 
 
+hb_unicode_get_mirroring_func_t
+hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->v.get_mirroring;
+}
+
+hb_unicode_get_general_category_func_t
+hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->v.get_general_category;
+}
+
+hb_unicode_get_script_func_t
+hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->v.get_script;
+}
+
+hb_unicode_get_combining_class_func_t
+hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->v.get_combining_class;
+}
+
+hb_unicode_get_eastasian_width_func_t
+hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs)
+{
+  return ufuncs->v.get_eastasian_width;
+}
+
+
+
 hb_codepoint_t
 hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
 			  hb_codepoint_t unicode)
 {
   return ufuncs->v.get_mirroring (unicode);
 }
 
 hb_category_t
@@ -295,21 +336,29 @@ const hb_direction_t horiz_dir[] =
   LTR,	/* Java */
   LTR,	/* Kthi */
   LTR,	/* Lisu */
   LTR,	/* Mtei */
   RTL,	/* Sarb */
   RTL,	/* Orkh */
   RTL,	/* Samr */
   LTR,	/* Lana */
-  LTR 	/* Tavt */
+  LTR,	/* Tavt */
+
+  /* Unicode-6.0 additions */
+  LTR,	/* Batk */
+  LTR,	/* Brah */
+  RTL 	/* Mand */
 };
 #undef LTR
 #undef RTL
 
 hb_direction_t
 _hb_script_get_horizontal_direction (hb_script_t script)
 {
   if (unlikely ((unsigned int) script >= ARRAY_LENGTH (horiz_dir)))
     return HB_DIRECTION_LTR;
 
   return horiz_dir[script];
 }
+
+
+HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-unicode.h
+++ b/gfx/harfbuzz/src/hb-unicode.h
@@ -26,16 +26,17 @@
 
 #ifndef HB_UNICODE_H
 #define HB_UNICODE_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
+
 /* Unicode General Category property */
 typedef enum
 {
   HB_CATEGORY_CONTROL,
   HB_CATEGORY_FORMAT,
   HB_CATEGORY_UNASSIGNED,
   HB_CATEGORY_PRIVATE_USE,
   HB_CATEGORY_SURROGATE,
@@ -162,17 +163,17 @@ typedef enum
   HB_SCRIPT_BAMUM,                  /* Bamu */
   HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,   /* Egyp */
   HB_SCRIPT_IMPERIAL_ARAMAIC,       /* Armi */
   HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,  /* Phli */
   HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Prti */
   HB_SCRIPT_JAVANESE,               /* Java */
   HB_SCRIPT_KAITHI,                 /* Kthi */
   HB_SCRIPT_LISU,                   /* Lisu */
-  HB_SCRIPT_MEITEI_MAYEK,           /* Mtei */
+  HB_SCRIPT_MEETEI_MAYEK,           /* Mtei */
   HB_SCRIPT_OLD_SOUTH_ARABIAN,      /* Sarb */
   HB_SCRIPT_OLD_TURKIC,             /* Orkh */
   HB_SCRIPT_SAMARITAN,              /* Samr */
   HB_SCRIPT_TAI_THAM,               /* Lana */
   HB_SCRIPT_TAI_VIET,               /* Tavt */
 
   /* Unicode-6.0 additions */
   HB_SCRIPT_BATAK,                  /* Batk */
@@ -200,26 +201,35 @@ void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
 
 hb_unicode_funcs_t *
 hb_unicode_funcs_copy (hb_unicode_funcs_t *ufuncs);
 
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
 
+hb_bool_t
+hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
 
-/* funcs */
+/*
+ * funcs
+ */
+
+
+/* typedefs */
 
 typedef hb_codepoint_t (*hb_unicode_get_mirroring_func_t) (hb_codepoint_t unicode);
 typedef hb_category_t (*hb_unicode_get_general_category_func_t) (hb_codepoint_t unicode);
 typedef hb_script_t (*hb_unicode_get_script_func_t) (hb_codepoint_t unicode);
 typedef unsigned int (*hb_unicode_get_combining_class_func_t) (hb_codepoint_t unicode);
 typedef unsigned int (*hb_unicode_get_eastasian_width_func_t) (hb_codepoint_t unicode);
 
 
+/* setters */
+
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
 				     hb_unicode_get_mirroring_func_t mirroring_func);
 
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
 					    hb_unicode_get_general_category_func_t general_category_func);
 
@@ -231,16 +241,38 @@ void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_get_combining_class_func_t combining_class_func);
 
 void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
 					   hb_unicode_get_eastasian_width_func_t eastasian_width_func);
 
 
+/* getters */
+
+/* These never return NULL.  Return fallback defaults instead. */
+
+hb_unicode_get_mirroring_func_t
+hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs);
+
+hb_unicode_get_general_category_func_t
+hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs);
+
+hb_unicode_get_script_func_t
+hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs);
+
+hb_unicode_get_combining_class_func_t
+hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs);
+
+hb_unicode_get_eastasian_width_func_t
+hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs);
+
+
+/* accessors */
+
 hb_codepoint_t
 hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
 			  hb_codepoint_t unicode);
 
 hb_category_t
 hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
 				 hb_codepoint_t unicode);
 
--- a/gfx/harfbuzz/src/hb.h
+++ b/gfx/harfbuzz/src/hb.h
@@ -30,9 +30,12 @@
 #include "hb-blob.h"
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-font.h"
 #include "hb-language.h"
 #include "hb-shape.h"
 #include "hb-unicode.h"
 
+HB_BEGIN_DECLS
+HB_END_DECLS
+
 #endif /* HB_H */
--- a/gfx/harfbuzz/src/main.cc
+++ b/gfx/harfbuzz/src/main.cc
@@ -30,16 +30,19 @@
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 #ifdef HAVE_GLIB
 #include <glib.h>
 #endif
 #include <stdlib.h>
 #include <stdio.h>
 
+HB_BEGIN_DECLS
+
+
 int
 main (int argc, char **argv)
 {
   if (argc != 2) {
     fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
     exit (1);
   }
 
@@ -153,18 +156,18 @@ main (int argc, char **argv)
 	            feature.get_lookup_index (n_lookup));
 	  }
 	}
 
 	int num_lookups = g.get_lookup_count ();
 	printf ("    %d lookup(s) found in table\n", num_lookups);
 	for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
 	  const Lookup &lookup = g.get_lookup (n_lookup);
-	  printf ("    Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups,
-	          lookup.get_type(), lookup.get_flag());
+	  printf ("    Lookup %2d of %2d: type %d, props 0x%04X\n", n_lookup, num_lookups,
+	          lookup.get_type(), lookup.get_props());
 	}
 
 	}
 	break;
 
       case GDEF::Tag:
 	{
 
@@ -183,8 +186,11 @@ main (int argc, char **argv)
 	break;
 	}
       }
     }
   }
 
   return 0;
 }
+
+
+HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/test.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+HB_BEGIN_DECLS
+
+
+int
+main (int argc, char **argv)
+{
+  hb_blob_t *blob = NULL;
+  hb_face_t *face = NULL;
+
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the blob */
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    fseek (f, 0, SEEK_END);
+    len = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    font_data = (const char *) malloc (len);
+    if (!font_data) len = 0;
+    len = fread ((char *) font_data, 1, len, f);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+#endif
+
+    blob = hb_blob_create (font_data, len,
+			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+			   destroy, user_data);
+  }
+
+  /* Create the face */
+  face = hb_face_create_for_data (blob, 0 /* first face */);
+
+  /* So, what now? */
+
+  hb_face_destroy (face);
+  hb_blob_destroy (blob);
+
+  return 0;
+}