bug 910506 - update harfbuzz to upstream release 0.9.21 plus latest bugfixes (commit 3d2c4f0c2ff8fab4262988aad65b170e5b479b20). r=jdaggett
authorJonathan Kew <jkew@mozilla.com>
Sat, 28 Sep 2013 09:51:46 +0100
changeset 149146 e087b5e210770acb17c2504b0f01ac8af62b9078
parent 149145 a3c49e27e3427897fec3ea215563af321861c412
child 149147 f98f80d2126ca8bd544fcf4e8d2e36ee40884ae5
push id25374
push usercbook@mozilla.com
push dateSun, 29 Sep 2013 09:37:16 +0000
treeherdermozilla-central@8f805d3ef377 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs910506
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 910506 - update harfbuzz to upstream release 0.9.21 plus latest bugfixes (commit 3d2c4f0c2ff8fab4262988aad65b170e5b479b20). r=jdaggett
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/check-c-linkage-decls.sh
gfx/harfbuzz/src/check-header-guards.sh
gfx/harfbuzz/src/check-includes.sh
gfx/harfbuzz/src/check-symbols.sh
gfx/harfbuzz/src/harfbuzz-gobject.pc.in
gfx/harfbuzz/src/harfbuzz-icu.pc.in
gfx/harfbuzz/src/harfbuzz.pc.in
gfx/harfbuzz/src/hb-blob.cc
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer-serialize.cc
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-buffer.h
gfx/harfbuzz/src/hb-common.cc
gfx/harfbuzz/src/hb-common.h
gfx/harfbuzz/src/hb-coretext.cc
gfx/harfbuzz/src/hb-deprecated.h
gfx/harfbuzz/src/hb-face-private.hh
gfx/harfbuzz/src/hb-face.cc
gfx/harfbuzz/src/hb-face.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.cc
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-gobject-enums.cc.tmpl
gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
gfx/harfbuzz/src/hb-gobject-structs.cc
gfx/harfbuzz/src/hb-gobject-structs.h
gfx/harfbuzz/src/hb-gobject.h
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-graphite2.h
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-head-table.hh
gfx/harfbuzz/src/hb-ot-hhea-table.hh
gfx/harfbuzz/src/hb-ot-hmtx-table.hh
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-jstf-table.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-maxp-table.hh
gfx/harfbuzz/src/hb-ot-name-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape-private.hh
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-set-private.hh
gfx/harfbuzz/src/hb-set.cc
gfx/harfbuzz/src/hb-set.h
gfx/harfbuzz/src/hb-shape-plan.cc
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-ucdn.cc
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-unicode.cc
gfx/harfbuzz/src/hb-unicode.h
gfx/harfbuzz/src/hb-uniscribe.cc
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/hb.h
gfx/harfbuzz/src/main.cc
gfx/harfbuzz/src/moz.build
gfx/harfbuzz/src/test-buffer-serialize.cc
gfx/thebes/gfxHarfBuzzShaper.cpp
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -23,16 +23,18 @@ HBSOURCES =  \
 	hb-buffer-deserialize-json.hh \
 	hb-buffer-deserialize-text.hh \
 	hb-buffer-private.hh \
 	hb-buffer-serialize.cc \
 	hb-buffer.cc \
 	hb-cache-private.hh \
 	hb-common.cc \
 	hb-fallback-shape.cc \
+	hb-face-private.hh \
+	hb-face.cc \
 	hb-font-private.hh \
 	hb-font.cc \
 	hb-mutex-private.hh \
 	hb-object-private.hh \
 	hb-open-file-private.hh \
 	hb-open-type-private.hh \
 	hb-ot-head-table.hh \
 	hb-ot-hhea-table.hh \
@@ -56,16 +58,18 @@ HBSOURCES =  \
 	hb-utf-private.hh \
 	hb-warning.cc \
 	$(NULL)
 HBHEADERS = \
 	hb.h \
 	hb-blob.h \
 	hb-buffer.h \
 	hb-common.h \
+	hb-deprecated.h \
+	hb-face.h \
 	hb-font.h \
 	hb-set.h \
 	hb-shape.h \
 	hb-shape-plan.h \
 	hb-unicode.h \
 	$(NULL)
 HBNODISTHEADERS = \
 	hb-version.h \
@@ -74,16 +78,17 @@ HBNODISTHEADERS = \
 if HAVE_OT
 HBSOURCES += \
 	hb-ot-layout.cc \
 	hb-ot-layout-common-private.hh \
 	hb-ot-layout-gdef-table.hh \
 	hb-ot-layout-gpos-table.hh \
 	hb-ot-layout-gsubgpos-private.hh \
 	hb-ot-layout-gsub-table.hh \
+	hb-ot-layout-jstf-table.hh \
 	hb-ot-layout-private.hh \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
 	hb-ot-shape.cc \
 	hb-ot-shape-complex-arabic.cc \
 	hb-ot-shape-complex-arabic-fallback.hh \
 	hb-ot-shape-complex-arabic-table.hh \
 	hb-ot-shape-complex-default.cc \
@@ -117,38 +122,16 @@ endif
 
 if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
 HBSOURCES += hb-glib.cc
 HBHEADERS += hb-glib.h
 endif
 
-if HAVE_GOBJECT
-HBCFLAGS += $(GOBJECT_CFLAGS)
-HBLIBS   += $(GOBJECT_LIBS)
-HBSOURCES += hb-gobject-structs.cc
-nodist_HBSOURCES = hb-gobject-enums.cc
-HBHEADERS += hb-gobject.h
-BUILT_SOURCES += hb-gobject-enums.cc
-EXTRA_DIST += hb-gobject-enums.cc.tmpl
-DISTCLEANFILES += hb-gobject-enums.cc
-
-hb-gobject-enums.cc: hb-gobject-enums.cc.tmpl $(HBHEADERS)
-	$(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > "$@.tmp" && \
-	mv "$@.tmp" "$@" || ( $(RM) "@.tmp" && false )
-endif
-
-if HAVE_ICU
-HBCFLAGS += $(ICU_CFLAGS)
-HBLIBS   += $(ICU_LIBS)
-HBSOURCES += hb-icu.cc
-HBHEADERS += hb-icu.h
-endif
-
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
 HBSOURCES += hb-ft.cc
 HBHEADERS += hb-ft.h
 endif
 
 if HAVE_GRAPHITE2
@@ -167,68 +150,107 @@ endif
 
 if HAVE_CORETEXT
 HBCFLAGS += $(CORETEXT_CFLAGS)
 HBLIBS   += $(CORETEXT_LIBS)
 HBSOURCES += hb-coretext.cc
 HBHEADERS += hb-coretext.h
 endif
 
-if HAVE_HB_OLD
-SUBDIRS += hb-old
-HBCFLAGS += -I$(srcdir)/hb-old
-HBLIBS   += hb-old/libhb-old.la
-HBSOURCES += hb-old.cc
-endif
-DIST_SUBDIRS += hb-old
-
-if HAVE_ICU_LE
-SUBDIRS += hb-icu-le
-HBCFLAGS += -I$(srcdir)/hb-icu-le
-HBLIBS   += hb-icu-le/libhb-icu-le.la
-HBSOURCES += hb-icu-le.cc
-endif
-DIST_SUBDIRS += hb-icu-le
-
 if HAVE_UCDN
 SUBDIRS += hb-ucdn
 HBCFLAGS += -I$(srcdir)/hb-ucdn
 HBLIBS   += hb-ucdn/libhb-ucdn.la
 HBSOURCES += hb-ucdn.cc
 endif
 DIST_SUBDIRS += hb-ucdn
 
 
 # Put the library together
 
 if OS_WIN32
 export_symbols = -export-symbols harfbuzz.def
 harfbuzz_def_dependency = harfbuzz.def
 libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
 else
-if HAVE_ICU
-libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
-else
 # Use a C linker for GCC, not C++; Don't link to libstdc++
 if HAVE_GCC
 libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
 else
 libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
 endif
 endif
-endif
 
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
-nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
 libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
 nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = harfbuzz.pc
+EXTRA_DIST += harfbuzz.pc.in
+
+if HAVE_ICU
+lib_LTLIBRARIES += libharfbuzz-icu.la
+libharfbuzz_icu_la_SOURCES = hb-icu.cc
+libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
+libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-icu.h
+pkgconfig_DATA += harfbuzz-icu.pc
+endif
+EXTRA_DIST += harfbuzz-icu.pc.in
+
+if HAVE_GOBJECT
+lib_LTLIBRARIES += libharfbuzz-gobject.la
+libharfbuzz_gobject_la_SOURCES = hb-gobject-structs.cc
+nodist_libharfbuzz_gobject_la_SOURCES = hb-gobject-enums.cc
+libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
+libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-gobject.h hb-gobject-structs.h
+nodist_pkginclude_HEADERS += hb-gobject-enums.h
+pkgconfig_DATA += harfbuzz-gobject.pc
+
+BUILT_SOURCES += \
+	hb-gobject-enums.cc \
+	hb-gobject-enums.h \
+	$(NULL)
+DISTCLEANFILES += \
+	hb-gobject-enums.cc \
+	hb-gobject-enums.h \
+	$(NULL)
+hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
+	$(AM_V_GEN) $(GLIB_MKENUMS) \
+		--identifier-prefix hb_ --symbol-prefix hb_gobject \
+		--template $^ | \
+	sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@.tmp" && \
+	mv "$@.tmp" "$@" || ( $(RM) "@.tmp" && false )
+endif
+EXTRA_DIST += \
+	harfbuzz-gobject.pc.in \
+	hb-gobject-enums.cc.tmpl \
+	hb-gobject-enums.h.tmpl \
+	$(NULL)
+
+
+%.pc: %.pc.in $(top_builddir)/config.status
+	$(AM_V_GEN) \
+	$(SED)	-e 's@%prefix%@$(prefix)@g' \
+		-e 's@%exec_prefix%@$(exec_prefix)@g' \
+		-e 's@%libdir%@$(libdir)@g' \
+		-e 's@%includedir%@$(includedir)@g' \
+		-e 's@%VERSION%@$(VERSION)@g' \
+	"$<" \
+	> "$@.tmp" && mv "$@.tmp" "$@" || ( $(RM) "$@.tmp"; false )
+
+CLEANFILES += $(pkgconfig_DATA)
+
 
 CLEANFILES += harfbuzz.def
 harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
 	$(AM_V_GEN) (echo EXPORTS; \
 	(cat $^ || echo 'hb_ERROR ()' ) | \
 	$(EGREP) '^hb_.* \(' | \
 	sed -e 's/ (.*//' | \
 	LANG=C sort; \
@@ -236,17 +258,16 @@ harfbuzz.def: $(HBHEADERS) $(HBNODISTHEA
 	) >"$@.tmp"
 	@ ! grep -q hb_ERROR "$@.tmp" && mv "$@.tmp" "$@" || ($(RM) "$@"; false)
 
 
 GENERATORS = \
 	gen-arabic-table.py \
 	gen-indic-table.py \
 	$(NULL)
-
 EXTRA_DIST += $(GENERATORS)
 
 unicode-tables: arabic-table indic-table
 
 indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
 	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc.tmp && \
 	mv hb-ot-shape-complex-indic-table.cc.tmp $(srcdir)/hb-ot-shape-complex-indic-table.cc || \
 	($(RM) hb-ot-shape-complex-indic-table.cc.tmp; false)
@@ -268,17 +289,17 @@ BUILT_SOURCES += \
 	$(NULL)
 EXTRA_DIST += \
 	hb-buffer-deserialize-json.rl \
 	hb-buffer-deserialize-text.rl \
 	hb-ot-shape-complex-indic-machine.rl \
 	hb-ot-shape-complex-myanmar-machine.rl \
 	hb-ot-shape-complex-sea-machine.rl \
 	$(NULL)
-%.hh: %.rl
+.rl.hh:
 	$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
 	mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
 
 noinst_PROGRAMS = \
 	main \
 	test \
 	test-buffer-serialize \
 	test-size-params \
@@ -303,54 +324,68 @@ test_size_params_CPPFLAGS = $(HBCFLAGS)
 test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
 
 test_buffer_serialize_SOURCES = test-buffer-serialize.cc
 test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
 test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
 
 dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
+	check-defs.sh \
 	check-header-guards.sh \
 	check-includes.sh \
+	check-libstdc++.sh \
+	check-static-inits.sh \
 	check-symbols.sh \
 	$(NULL)
 
-if HAVE_ICU
-else
-dist_check_SCRIPTS += check-libstdc++.sh
-endif
-
-if HAVE_ICU_LE
-else
-dist_check_SCRIPTS += check-static-inits.sh
-endif
-
 TESTS = $(dist_check_SCRIPTS)
 TESTS_ENVIRONMENT = \
 	srcdir="$(srcdir)" \
 	MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
 	HBSOURCES="$(HBSOURCES)" \
 	HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
 	$(NULL)
 
-#-include $(INTROSPECTION_MAKEFILE)
-#INTROSPECTION_GIRS = hb-1.0.gir
-#INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_
-#INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
-#
-#if HAVE_INTROSPECTION
-#
-#hb-1.0.gir: libharfbuzz.la
-#hb_1_0_gir_INCLUDES = GObject-2.0
-#hb_1_0_gir_CFLAGS = $(INCLUDES) $(HBCFLAGS) -DHB_H -DHB_H_IN -DHB_OT_H -DHB_OT_H_IN
-#hb_1_0_gir_LIBS = libharfbuzz.la
-#hb_1_0_gir_FILES = $(HBHEADERS) $(HBNODISTHEADERS)
-#
-#girdir = $(datadir)/gir-1.0
-#gir_DATA = $(INTROSPECTION_GIRS)
-#
-#typelibdir = $(libdir)/girepository-1.0
-#typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
-#
-#CLEANFILES += $(gir_DATA) $(typelib_DATA)
-#endif
+if HAVE_INTROSPECTION
+
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
+INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+
+HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
+HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
+HarfBuzz_0_0_gir_CFLAGS = \
+	$(INCLUDES) \
+	$(HBCFLAGS) \
+	-DHB_H \
+	-DHB_H_IN \
+	-DHB_OT_H \
+	-DHB_OT_H_IN \
+	-DHB_GOBJECT_H \
+	-DHB_GOBJECT_H_IN \
+	$(NULL)
+HarfBuzz_0_0_gir_LIBS = \
+	libharfbuzz.la \
+	libharfbuzz-gobject.la \
+	$(NULL)
+HarfBuzz_0_0_gir_FILES = \
+	$(HBHEADERS) \
+	$(HBNODISTHEADERS) \
+	$(HBSOURCES) \
+	hb-gobject-enums.cc \
+	hb-gobject-enums.h \
+	hb-gobject-structs.cc \
+	hb-gobject-structs.h \
+	$(NULL)
+
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+
+endif
 
 -include $(top_srcdir)/git.mk
--- a/gfx/harfbuzz/src/check-c-linkage-decls.sh
+++ b/gfx/harfbuzz/src/check-c-linkage-decls.sh
@@ -1,18 +1,18 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 
 
 for x in $HBHEADERS; do
 	test -f $srcdir/$x && x=$srcdir/$x
 	if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
 		echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
 		stat=1
 	fi
--- a/gfx/harfbuzz/src/check-header-guards.sh
+++ b/gfx/harfbuzz/src/check-header-guards.sh
@@ -1,18 +1,18 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 
 for x in $HBHEADERS $HBSOURCES; do
 	test -f "$srcdir/$x" && x="$srcdir/$x"
 	echo "$x" | grep '[^h]$' -q && continue;
 	xx=`echo "$x" | sed 's@.*/@@'`
 	tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
 	lines=`grep "\<$tag\>" "$x" | wc -l | sed 's/[ 	]*//g'`
--- a/gfx/harfbuzz/src/check-includes.sh
+++ b/gfx/harfbuzz/src/check-includes.sh
@@ -1,42 +1,44 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
-
-
-cd "$srcdir"
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 
 echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
 
 for x in $HBHEADERS; do
+	test -f "$srcdir/$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | head -n 1
 done |
 grep -v '"hb-common[.]h"' |
 grep -v '"hb[.]h"' |
 grep -v 'hb-common[.]h:' |
 grep -v 'hb[.]h:' |
 grep . >&2 && stat=1
 
 
 echo 'Checking that source files #include "hb-*private.hh" first (or none)'
 
 for x in $HBSOURCES; do
+	test -f "$srcdir/$x" && x="$srcdir/$x"
 	grep '#.*\<include\>' "$x" /dev/null | head -n 1
 done |
 grep -v '"hb-.*private[.]hh"' |
 grep -v 'hb-private[.]hh:' |
 grep . >&2 && stat=1
 
 
 echo 'Checking that there is no #include <hb.*.h>'
-grep '#.*\<include\>.*<.*hb' $HBHEADERS $HBSOURCES >&2 && stat=1
+for x in $HBHEADERS $HBSOURCES; do
+	test -f "$srcdir/$x" && x="$srcdir/$x"
+	grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1
+done
 
 
 exit $stat
--- a/gfx/harfbuzz/src/check-symbols.sh
+++ b/gfx/harfbuzz/src/check-symbols.sh
@@ -1,50 +1,37 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
-test -z "$MAKE" && MAKE=make
 stat=0
 
+
 if which nm 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-symbols.sh: 'nm' not found; skipping test"
 	exit 77
 fi
 
-defs="harfbuzz.def"
-$MAKE $defs > /dev/null
+echo "Checking that we are not exposing internal symbols"
 tested=false
-for def in $defs; do
-	lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
-	so=.libs/lib${lib}.so
-
+for so in `ls .libs/lib*.so .libs/lib*.dylib 2>/dev/null` ; do
+	
 	EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3`"
-
-	if test -f "$so"; then
+	prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
 
-		echo "Checking that $so has the same symbol list as $def"
-		{
-			echo EXPORTS
-			echo "$EXPORTED_SYMBOLS"
-			# cheat: copy the last line from the def file!
-			tail -n1 "$def"
-		} | diff "$def" - >&2 || stat=1
+	echo "Processing $so"
+	if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}_"; then
+		echo "Ouch, internal symbols exposed"
+		stat=1
+	fi
 
-		echo "Checking that we are not exposing internal symbols"
-		if echo "$EXPORTED_SYMBOLS" | grep -v 'hb_'; then
-			echo "Ouch, internal symbols exposed"
-			stat=1
-		fi
-
-		tested=true
-	fi
+	tested=true
 done
 if ! $tested; then
-	echo "check-exported-symbols.sh: libharfbuzz shared library not found; skipping test"
+	echo "check-symbols.sh: no shared library found; skipping test"
 	exit 77
 fi
 
 exit $stat
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/harfbuzz-gobject.pc.in
@@ -0,0 +1,12 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library GObject integration
+Version: %VERSION%
+
+Requires: harfbuzz gobject-2.0 glib-2.0
+Libs: -L${libdir} -lharfbuzz-gobject
+Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/harfbuzz-icu.pc.in
@@ -0,0 +1,13 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library ICU integration
+Version: %VERSION%
+
+Requires: harfbuzz
+Requires.private: icu-uc
+Libs: -L${libdir} -lharfbuzz-icu
+Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/harfbuzz.pc.in
@@ -0,0 +1,11 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library
+Version: %VERSION%
+
+Libs: -L${libdir} -lharfbuzz
+Cflags: -I${includedir}/harfbuzz
--- a/gfx/harfbuzz/src/hb-blob.cc
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -71,16 +71,32 @@ static void
 {
   if (blob->destroy) {
     blob->destroy (blob->user_data);
     blob->user_data = NULL;
     blob->destroy = NULL;
   }
 }
 
+/**
+ * hb_blob_create: (Xconstructor)
+ * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data.  The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Return value: New blob, or the empty blob if something failed or if @length is
+ * zero.  Destroy with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_create (const char        *data,
 		unsigned int       length,
 		hb_memory_mode_t   mode,
 		void              *user_data,
 		hb_destroy_func_t  destroy)
 {
   hb_blob_t *blob;
@@ -104,16 +120,36 @@ hb_blob_create (const char        *data,
       hb_blob_destroy (blob);
       return hb_blob_get_empty ();
     }
   }
 
   return blob;
 }
 
+/**
+ * hb_blob_create_sub_blob:
+ * @parent: Parent blob.
+ * @offset: Start offset of sub-blob within @parent, in bytes.
+ * @length: Length of sub-blob.
+ *
+ * Returns a blob that represents a range of bytes in @parent.  The new
+ * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * will never modify data in the parent blob.  The parent data is not
+ * expected to be modified, and will result in undefined behavior if it
+ * is.
+ *
+ * Makes @parent immutable.
+ *
+ * Return value: New blob, or the empty blob if something failed or if
+ * @length is zero or @offset is beyond the end of @parent's data.  Destroy
+ * with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
 			 unsigned int  offset,
 			 unsigned int  length)
 {
   hb_blob_t *blob;
 
   if (!length || offset >= parent->length)
@@ -125,16 +161,27 @@ hb_blob_create_sub_blob (hb_blob_t    *p
 			 MIN (length, parent->length - offset),
 			 HB_MEMORY_MODE_READONLY,
 			 hb_blob_reference (parent),
 			 (hb_destroy_func_t) hb_blob_destroy);
 
   return blob;
 }
 
+/**
+ * hb_blob_get_empty:
+ *
+ * Returns the singleton empty blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: (transfer full): the empty blob.
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_get_empty (void)
 {
   static const hb_blob_t _hb_blob_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* immutable */
 
@@ -144,81 +191,183 @@ hb_blob_get_empty (void)
 
     NULL, /* user_data */
     NULL  /* destroy */
   };
 
   return const_cast<hb_blob_t *> (&_hb_blob_nil);
 }
 
+/**
+ * hb_blob_reference: (skip)
+ * @blob: a blob.
+ *
+ * Increases the reference count on @blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: @blob.
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_reference (hb_blob_t *blob)
 {
   return hb_object_reference (blob);
 }
 
+/**
+ * hb_blob_destroy: (skip)
+ * @blob: a blob.
+ *
+ * Descreases the reference count on @blob, and if it reaches zero, destroys
+ * @blob, freeing all memory, possibly calling the destroy-callback the blob
+ * was created for if it has not been called already.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Since: 1.0
+ **/
 void
 hb_blob_destroy (hb_blob_t *blob)
 {
   if (!hb_object_destroy (blob)) return;
 
   _hb_blob_destroy_user_data (blob);
 
   free (blob);
 }
 
+/**
+ * hb_blob_set_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to set.
+ * @data: data to set.
+ * @destroy: callback to call when @data is not needed anymore.
+ * @replace: whether to replace an existing data with the same key.
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_blob_set_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key,
 		       void *              data,
 		       hb_destroy_func_t   destroy,
 		       hb_bool_t           replace)
 {
   return hb_object_set_user_data (blob, key, data, destroy, replace);
 }
 
+/**
+ * hb_blob_get_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to get.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_blob_get_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (blob, key);
 }
 
 
+/**
+ * hb_blob_make_immutable:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_blob_make_immutable (hb_blob_t *blob)
 {
   if (hb_object_is_inert (blob))
     return;
 
   blob->immutable = true;
 }
 
+/**
+ * hb_blob_is_immutable:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Return value: TODO
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_blob_is_immutable (hb_blob_t *blob)
 {
   return blob->immutable;
 }
 
 
+/**
+ * hb_blob_get_length:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Return value: the length of blob data in bytes.
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_blob_get_length (hb_blob_t *blob)
 {
   return blob->length;
 }
 
+/**
+ * hb_blob_get_data:
+ * @blob: a blob.
+ * @length: (out):
+ *
+ * 
+ *
+ * Returns: (transfer none) (array length=length): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
 {
   if (length)
     *length = blob->length;
 
   return blob->data;
 }
 
+/**
+ * hb_blob_get_data_writable:
+ * @blob: a blob.
+ * @length: (out): output length of the writable data.
+ *
+ * Tries to make blob data writable (possibly copying it) and
+ * return pointer to data.
+ *
+ * Fails if blob has been made immutable, or if memory allocation
+ * fails.
+ *
+ * Returns: (transfer none) (array length=length): Writable blob data,
+ * or %NULL if failed.
+ *
+ * Since: 1.0
+ **/
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
 {
   if (!_try_writable (blob)) {
     if (length)
       *length = 0;
 
     return NULL;
@@ -319,10 +468,8 @@ static bool
   _hb_blob_destroy_user_data (blob);
   blob->mode = HB_MEMORY_MODE_WRITABLE;
   blob->data = new_data;
   blob->user_data = new_data;
   blob->destroy = free;
 
   return true;
 }
-
-
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -75,16 +75,18 @@ struct hb_buffer_t {
   inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
 
   inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
   inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
 
   inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
   inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
 
+  inline bool has_separate_output (void) const { return info != out_info; }
+
   unsigned int serial;
 
   /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
   uint8_t allocated_var_bytes[8];
   const char *allocated_var_owner[8];
 
   /* Text before / after the main buffer contents.
    * Always in Unicode, and ordered outward.
--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc
+++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc
@@ -28,29 +28,59 @@
 
 
 static const char *serialize_formats[] = {
   "text",
   "json",
   NULL
 };
 
+/**
+ * hb_buffer_serialize_list_formats:
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 const char **
 hb_buffer_serialize_list_formats (void)
 {
   return serialize_formats;
 }
 
+/**
+ * hb_buffer_serialize_format_from_string:
+ * @str: 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_buffer_serialize_format_t
 hb_buffer_serialize_format_from_string (const char *str, int len)
 {
   /* Upper-case it. */
   return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020);
 }
 
+/**
+ * hb_buffer_serialize_format_to_string:
+ * @format: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
 {
   switch (format)
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
     default:
@@ -95,20 +125,20 @@ static unsigned int
       for (char *q = g; *q; q++) {
         if (*q == '"')
 	  *p++ = '\\';
 	*p++ = *q;
       }
       *p++ = '"';
     }
     else
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
 		     pos[i].x_offset, pos[i].y_offset);
       p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
 		     pos[i].x_advance, pos[i].y_advance);
@@ -156,31 +186,31 @@ static unsigned int
       *p++ = '|';
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
     {
       hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
       p += strlen (p);
     }
     else
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
     }
 
     if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
     {
       if (pos[i].x_offset || pos[i].y_offset)
-	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset);
+	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
 
       *p++ = '+';
-      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance);
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
       if (pos->y_advance)
-	p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance);
+	p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
     }
 
     if (buf_size > (p - b))
     {
       unsigned int l = p - b;
       memcpy (buf, b, l);
       buf += l;
       buf_size -= l;
@@ -189,16 +219,34 @@ static unsigned int
     } else
       return i - start;
   }
 
   return end - start;
 }
 
 /* Returns number of items, starting at start, that were serialized. */
+/**
+ * hb_buffer_serialize_glyphs:
+ * @buffer: a buffer.
+ * @start: 
+ * @end: 
+ * @buf: (array length=buf_size):
+ * @buf_size: 
+ * @buf_consumed: (out):
+ * @font: 
+ * @format: 
+ * @flags: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
 			    unsigned int start,
 			    unsigned int end,
 			    char *buf,
 			    unsigned int buf_size,
 			    unsigned int *buf_consumed, /* May be NULL */
 			    hb_font_t *font, /* May be NULL */
@@ -281,16 +329,31 @@ parse_int (const char *pp, const char *e
 
   *pv = v;
   return true;
 }
 
 #include "hb-buffer-deserialize-json.hh"
 #include "hb-buffer-deserialize-text.hh"
 
+/**
+ * hb_buffer_deserialize_glyphs:
+ * @buffer: a buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len: 
+ * @end_ptr: (out):
+ * @font: 
+ * @format: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
 			      const char *buf,
 			      int buf_len, /* -1 means nul-terminated */
 			      const char **end_ptr, /* May be NULL */
 			      hb_font_t *font, /* May be NULL */
 			      hb_buffer_serialize_format_t format)
 {
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -171,17 +171,17 @@ hb_buffer_t::reset (void)
 void
 hb_buffer_t::clear (void)
 {
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
-  flags = HB_BUFFER_FLAGS_DEFAULT;
+  flags = HB_BUFFER_FLAG_DEFAULT;
 
   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   in_error = false;
   have_output = false;
   have_positions = false;
 
   idx = 0;
   len = 0;
@@ -544,49 +544,49 @@ dump_var_allocation (const hb_buffer_t *
 	     "Current var allocation: %s",
 	     buf);
 }
 
 void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
 {
   assert (byte_i < 8 && byte_i + count <= 8);
 
-  if (DEBUG (BUFFER))
+  if (DEBUG_ENABLED (BUFFER))
     dump_var_allocation (this);
   DEBUG_MSG (BUFFER, this,
 	     "Allocating var bytes %d..%d for %s",
 	     byte_i, byte_i + count - 1, owner);
 
   for (unsigned int i = byte_i; i < byte_i + count; i++) {
     assert (!allocated_var_bytes[i]);
     allocated_var_bytes[i]++;
     allocated_var_owner[i] = owner;
   }
 }
 
 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
 {
-  if (DEBUG (BUFFER))
+  if (DEBUG_ENABLED (BUFFER))
     dump_var_allocation (this);
 
   DEBUG_MSG (BUFFER, this,
 	     "Deallocating var bytes %d..%d for %s",
 	     byte_i, byte_i + count - 1, owner);
 
   assert (byte_i < 8 && byte_i + count <= 8);
   for (unsigned int i = byte_i; i < byte_i + count; i++) {
     assert (allocated_var_bytes[i]);
     assert (0 == strcmp (allocated_var_owner[i], owner));
     allocated_var_bytes[i]--;
   }
 }
 
 void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
 {
-  if (DEBUG (BUFFER))
+  if (DEBUG_ENABLED (BUFFER))
     dump_var_allocation (this);
 
   DEBUG_MSG (BUFFER, this,
 	     "Asserting var bytes %d..%d for %s",
 	     byte_i, byte_i + count - 1, owner);
 
   assert (byte_i < 8 && byte_i + count <= 8);
   for (unsigned int i = byte_i; i < byte_i + count; i++) {
@@ -598,240 +598,491 @@ void hb_buffer_t::assert_var (unsigned i
 void hb_buffer_t::deallocate_var_all (void)
 {
   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
   memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
 }
 
 /* Public API */
 
+/**
+ * hb_buffer_create: (Xconstructor)
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
 hb_buffer_create (void)
 {
   hb_buffer_t *buffer;
 
   if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return hb_buffer_get_empty ();
 
   buffer->reset ();
 
   return buffer;
 }
 
+/**
+ * hb_buffer_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
 hb_buffer_get_empty (void)
 {
   static const hb_buffer_t _hb_buffer_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
     HB_SEGMENT_PROPERTIES_DEFAULT,
-    HB_BUFFER_FLAGS_DEFAULT,
+    HB_BUFFER_FLAG_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     true, /* in_error */
     true, /* have_output */
     true  /* have_positions */
 
     /* Zero is good enough for everything else. */
   };
 
   return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
 }
 
+/**
+ * hb_buffer_reference: (skip)
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer)
 {
   return hb_object_reference (buffer);
 }
 
+/**
+ * hb_buffer_destroy: (skip)
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_destroy (hb_buffer_t *buffer)
 {
   if (!hb_object_destroy (buffer)) return;
 
   hb_unicode_funcs_destroy (buffer->unicode);
 
   free (buffer->info);
   free (buffer->pos);
 
   free (buffer);
 }
 
+/**
+ * hb_buffer_set_user_data: (skip)
+ * @buffer: a buffer.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_set_user_data (hb_buffer_t        *buffer,
 			 hb_user_data_key_t *key,
 			 void *              data,
 			 hb_destroy_func_t   destroy,
 			 hb_bool_t           replace)
 {
   return hb_object_set_user_data (buffer, key, data, destroy, replace);
 }
 
+/**
+ * hb_buffer_get_user_data: (skip)
+ * @buffer: a buffer.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_buffer_get_user_data (hb_buffer_t        *buffer,
 			 hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (buffer, key);
 }
 
 
+/**
+ * hb_buffer_set_content_type:
+ * @buffer: a buffer.
+ * @content_type: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_content_type (hb_buffer_t              *buffer,
 			    hb_buffer_content_type_t  content_type)
 {
   buffer->content_type = content_type;
 }
 
+/**
+ * hb_buffer_get_content_type:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_buffer_content_type_t
 hb_buffer_get_content_type (hb_buffer_t *buffer)
 {
   return buffer->content_type;
 }
 
 
+/**
+ * hb_buffer_set_unicode_funcs:
+ * @buffer: a buffer.
+ * @unicode_funcs: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
-			     hb_unicode_funcs_t *unicode)
+			     hb_unicode_funcs_t *unicode_funcs)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
-  if (!unicode)
-    unicode = hb_unicode_funcs_get_default ();
+  if (!unicode_funcs)
+    unicode_funcs = hb_unicode_funcs_get_default ();
 
 
-  hb_unicode_funcs_reference (unicode);
+  hb_unicode_funcs_reference (unicode_funcs);
   hb_unicode_funcs_destroy (buffer->unicode);
-  buffer->unicode = unicode;
+  buffer->unicode = unicode_funcs;
 }
 
+/**
+ * hb_buffer_get_unicode_funcs:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
 {
   return buffer->unicode;
 }
 
+/**
+ * hb_buffer_set_direction:
+ * @buffer: a buffer.
+ * @direction: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
 			 hb_direction_t  direction)
 
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   buffer->props.direction = direction;
 }
 
+/**
+ * hb_buffer_get_direction:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_buffer_get_direction (hb_buffer_t    *buffer)
 {
   return buffer->props.direction;
 }
 
+/**
+ * hb_buffer_set_script:
+ * @buffer: a buffer.
+ * @script: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_script (hb_buffer_t *buffer,
 		      hb_script_t  script)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   buffer->props.script = script;
 }
 
+/**
+ * hb_buffer_get_script:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer)
 {
   return buffer->props.script;
 }
 
+/**
+ * hb_buffer_set_language:
+ * @buffer: a buffer.
+ * @language: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
 			hb_language_t  language)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   buffer->props.language = language;
 }
 
+/**
+ * hb_buffer_get_language:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
 {
   return buffer->props.language;
 }
 
+/**
+ * hb_buffer_set_segment_properties:
+ * @buffer: a buffer.
+ * @props: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_segment_properties (hb_buffer_t *buffer,
 				  const hb_segment_properties_t *props)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   buffer->props = *props;
 }
 
+/**
+ * hb_buffer_get_segment_properties:
+ * @buffer: a buffer.
+ * @props: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
 				  hb_segment_properties_t *props)
 {
   *props = buffer->props;
 }
 
 
+/**
+ * hb_buffer_set_flags:
+ * @buffer: a buffer.
+ * @flags: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_flags (hb_buffer_t       *buffer,
 		     hb_buffer_flags_t  flags)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   buffer->flags = flags;
 }
 
+/**
+ * hb_buffer_get_flags:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_buffer_flags_t
 hb_buffer_get_flags (hb_buffer_t *buffer)
 {
   return buffer->flags;
 }
 
 
+/**
+ * hb_buffer_reset:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reset (hb_buffer_t *buffer)
 {
   buffer->reset ();
 }
 
+/**
+ * hb_buffer_clear_contents:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_clear_contents (hb_buffer_t *buffer)
 {
   buffer->clear ();
 }
 
+/**
+ * hb_buffer_pre_allocate:
+ * @buffer: a buffer.
+ * @size: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
 {
   return buffer->ensure (size);
 }
 
+/**
+ * hb_buffer_allocation_successful:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
 {
   return !buffer->in_error;
 }
 
+/**
+ * hb_buffer_add:
+ * @buffer: a buffer.
+ * @codepoint: 
+ * @cluster: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add (hb_buffer_t    *buffer,
 	       hb_codepoint_t  codepoint,
 	       unsigned int    cluster)
 {
   buffer->add (codepoint, cluster);
   buffer->clear_context (1);
 }
 
+/**
+ * hb_buffer_set_length:
+ * @buffer: a buffer.
+ * @length: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
 		      unsigned int  length)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return length == 0;
 
   if (!buffer->ensure (length))
@@ -848,59 +1099,133 @@ hb_buffer_set_length (hb_buffer_t  *buff
 
   if (!length)
     buffer->clear_context (0);
   buffer->clear_context (1);
 
   return true;
 }
 
+/**
+ * hb_buffer_get_length:
+ * @buffer: a buffer.
+ *
+ * Returns the number of items in the buffer.
+ *
+ * Return value: buffer length.
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer)
 {
   return buffer->len;
 }
 
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_infos:
+ * @buffer: a buffer.
+ * @length: (out): output array length.
+ *
+ * Returns buffer glyph information array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph information array.
+ *
+ * Since: 1.0
+ **/
 hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
                            unsigned int *length)
 {
   if (length)
     *length = buffer->len;
 
   return (hb_glyph_info_t *) buffer->info;
 }
 
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_positions:
+ * @buffer: a buffer.
+ * @length: (out): output length.
+ *
+ * Returns buffer glyph position array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph position array.
+ *
+ * Since: 1.0
+ **/
 hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                                unsigned int *length)
 {
   if (!buffer->have_positions)
     buffer->clear_positions ();
 
   if (length)
     *length = buffer->len;
 
   return (hb_glyph_position_t *) buffer->pos;
 }
 
+/**
+ * hb_buffer_reverse:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reverse (hb_buffer_t *buffer)
 {
   buffer->reverse ();
 }
 
+/**
+ * hb_buffer_reverse_clusters:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer clusters.  That is, the buffer contents are
+ * reversed, then each cluster (consecutive items having the
+ * same cluster number) are reversed again.
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
 {
   buffer->reverse_clusters ();
 }
 
+/**
+ * hb_buffer_guess_segment_properties:
+ * @buffer: a buffer.
+ *
+ * Sets unset buffer segment properties based on buffer Unicode
+ * contents.  If buffer is not empty, it must have content type
+ * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ *
+ * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * will be set to the Unicode script of the first character in
+ * the buffer that has a script other than %HB_SCRIPT_COMMON,
+ * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ *
+ * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * it will be set to the natural horizontal direction of the
+ * buffer script as returned by hb_script_get_horizontal_direction().
+ *
+ * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * it will be set to the process's default language as returned by
+ * hb_language_get_default().  This may change in the future by
+ * taking buffer script into consideration when choosing a language.
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
 {
   buffer->guess_segment_properties ();
 }
 
 template <typename T>
 static inline void
@@ -963,36 +1288,72 @@ hb_buffer_add_utf (hb_buffer_t  *buffer,
     hb_codepoint_t u;
     next = hb_utf_next (next, end, &u);
     buffer->context[1][buffer->context_len[1]++] = u;
   }
 
   buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
 }
 
+/**
+ * hb_buffer_add_utf8:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
 		    const char   *text,
 		    int           text_length,
 		    unsigned int  item_offset,
 		    int           item_length)
 {
   hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
 }
 
+/**
+ * hb_buffer_add_utf16:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
 		     const uint16_t *text,
 		     int             text_length,
 		     unsigned int    item_offset,
-		     int            item_length)
+		     int             item_length)
 {
   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
 }
 
+/**
+ * hb_buffer_add_utf32:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
 		     const uint32_t *text,
 		     int             text_length,
 		     unsigned int    item_offset,
 		     int             item_length)
 {
   hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length);
@@ -1049,16 +1410,24 @@ normalize_glyphs_cluster (hb_buffer_t *b
     for (unsigned int i = start + 1; i < end; i++) {
       pos[i].x_offset -= total_x_advance;
       pos[i].y_offset -= total_y_advance;
     }
     hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
   }
 }
 
+/**
+ * hb_buffer_normalize_glyphs:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
 {
   assert (buffer->have_positions);
   assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
 
   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -166,18 +166,18 @@ hb_buffer_set_segment_properties (hb_buf
 void
 hb_buffer_get_segment_properties (hb_buffer_t *buffer,
 				  hb_segment_properties_t *props);
 
 void
 hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
 
 
-typedef enum {
-  HB_BUFFER_FLAGS_DEFAULT			= 0x00000000,
+typedef enum { /*< flags >*/
+  HB_BUFFER_FLAG_DEFAULT			= 0x00000000,
   HB_BUFFER_FLAG_BOT				= 0x00000001, /* Beginning-of-text */
   HB_BUFFER_FLAG_EOT				= 0x00000002, /* End-of-text */
   HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES	= 0x00000004
 } hb_buffer_flags_t;
 
 void
 hb_buffer_set_flags (hb_buffer_t       *buffer,
 		     hb_buffer_flags_t  flags);
@@ -269,18 +269,18 @@ hb_buffer_get_glyph_positions (hb_buffer
 void
 hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
 
 
 /*
  * Serialize
  */
 
-typedef enum {
-  HB_BUFFER_SERIALIZE_FLAGS_DEFAULT		= 0x00000000,
+typedef enum { /*< flags >*/
+  HB_BUFFER_SERIALIZE_FLAG_DEFAULT		= 0x00000000,
   HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS		= 0x00000001,
   HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS		= 0x00000002,
   HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES	= 0x00000004
 } hb_buffer_serialize_flags_t;
 
 typedef enum {
   HB_BUFFER_SERIALIZE_FORMAT_TEXT	= HB_TAG('T','E','X','T'),
   HB_BUFFER_SERIALIZE_FORMAT_JSON	= HB_TAG('J','S','O','N'),
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -52,35 +52,55 @@ void
 
   /* This is idempotent and threadsafe. */
   _hb_options = u;
 }
 
 
 /* hb_tag_t */
 
+/**
+ * hb_tag_from_string:
+ * @str: (array length=len): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_tag_t
-hb_tag_from_string (const char *s, int len)
+hb_tag_from_string (const char *str, int len)
 {
   char tag[4];
   unsigned int i;
 
-  if (!s || !len || !*s)
+  if (!str || !len || !*str)
     return HB_TAG_NONE;
 
   if (len < 0 || len > 4)
     len = 4;
-  for (i = 0; i < (unsigned) len && s[i]; i++)
-    tag[i] = s[i];
+  for (i = 0; i < (unsigned) len && str[i]; i++)
+    tag[i] = str[i];
   for (; i < 4; i++)
     tag[i] = ' ';
 
   return HB_TAG_CHAR4 (tag);
 }
 
+/**
+ * hb_tag_to_string:
+ * @tag: 
+ * @buf: (array fixed-size=4): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_tag_to_string (hb_tag_t tag, char *buf)
 {
   buf[0] = (char) (uint8_t) (tag >> 24);
   buf[1] = (char) (uint8_t) (tag >> 16);
   buf[2] = (char) (uint8_t) (tag >>  8);
   buf[3] = (char) (uint8_t) (tag >>  0);
 }
@@ -90,16 +110,27 @@ hb_tag_to_string (hb_tag_t tag, char *bu
 
 const char direction_strings[][4] = {
   "ltr",
   "rtl",
   "ttb",
   "btt"
 };
 
+/**
+ * hb_direction_from_string:
+ * @str: (array length=len): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_direction_from_string (const char *str, int len)
 {
   if (unlikely (!str || !len || !*str))
     return HB_DIRECTION_INVALID;
 
   /* Lets match loosely: just match the first letter, such that
    * all of "ltr", "left-to-right", etc work!
@@ -107,16 +138,26 @@ hb_direction_from_string (const char *st
   char c = TOLOWER (str[0]);
   for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
     if (c == direction_strings[i][0])
       return (hb_direction_t) (HB_DIRECTION_LTR + i);
 
   return HB_DIRECTION_INVALID;
 }
 
+/**
+ * hb_direction_to_string:
+ * @direction: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_direction_to_string (hb_direction_t direction)
 {
   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
 	      < ARRAY_LENGTH (direction_strings)))
     return direction_strings[direction - HB_DIRECTION_LTR];
 
   return "invalid";
@@ -182,17 +223,17 @@ struct hb_language_item_t {
   inline hb_language_item_t & operator = (const char *s) {
     lang = (hb_language_t) strdup (s);
     for (unsigned char *p = (unsigned char *) lang; *p; p++)
       *p = canon_map[*p];
 
     return *this;
   }
 
-  void finish (void) { free (lang); }
+  void finish (void) { free ((void *) lang); }
 };
 
 
 /* Thread-safe lock-free language list */
 
 static hb_language_item_t *langs;
 
 static inline
@@ -232,41 +273,73 @@ retry:
   if (!first_lang)
     atexit (free_langs); /* First person registers atexit() callback. */
 #endif
 
   return lang;
 }
 
 
+/**
+ * hb_language_from_string:
+ * @str: (array length=len): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_language_from_string (const char *str, int len)
 {
+  char strbuf[64];
+
   if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
-  char strbuf[32];
-  if (len >= 0) {
+  if (len >= 0)
+  {
     len = MIN (len, (int) sizeof (strbuf) - 1);
     str = (char *) memcpy (strbuf, str, len);
     strbuf[len] = '\0';
   }
 
   hb_language_item_t *item = lang_find_or_insert (str);
 
   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
 }
 
+/**
+ * hb_language_to_string:
+ * @language: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_language_to_string (hb_language_t language)
 {
   /* This is actually NULL-safe! */
   return language->s;
 }
 
+/**
+ * hb_language_get_default:
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_language_get_default (void)
 {
   static hb_language_t default_language = HB_LANGUAGE_INVALID;
 
   hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
   if (unlikely (language == HB_LANGUAGE_INVALID)) {
     language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
@@ -274,16 +347,26 @@ hb_language_get_default (void)
   }
 
   return default_language;
 }
 
 
 /* hb_script_t */
 
+/**
+ * hb_script_from_iso15924_tag:
+ * @tag: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag)
 {
   if (unlikely (tag == HB_TAG_NONE))
     return HB_SCRIPT_INVALID;
 
   /* Be lenient, adjust case (one capital letter followed by three small letters) */
   tag = (tag & 0xDFDFDFDF) | 0x00202020;
@@ -308,28 +391,59 @@ hb_script_from_iso15924_tag (hb_tag_t ta
   /* If it looks right, just use the tag as a script */
   if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
     return (hb_script_t) tag;
 
   /* Otherwise, return unknown */
   return HB_SCRIPT_UNKNOWN;
 }
 
+/**
+ * hb_script_from_string:
+ * @s: (array length=len): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_script_from_string (const char *s, int len)
 {
   return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
 }
 
+/**
+ * hb_script_to_iso15924_tag:
+ * @script: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script)
 {
   return (hb_tag_t) script;
 }
 
+/**
+ * hb_script_get_horizontal_direction:
+ * @script: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script)
 {
   /* http://goo.gl/x9ilM */
   switch ((hb_tag_t) script)
   {
     /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
@@ -404,31 +518,62 @@ hb_user_data_array_t::get (hb_user_data_
   hb_user_data_item_t item = {NULL };
 
   return items.find (key, &item, lock) ? item.data : NULL;
 }
 
 
 /* hb_version */
 
+/**
+ * hb_version:
+ * @major: (out): Library major version component.
+ * @minor: (out): Library minor version component.
+ * @micro: (out): Library micro version component.
+ *
+ * Returns library version as three integer components.
+ *
+ * Since: 1.0
+ **/
 void
 hb_version (unsigned int *major,
 	    unsigned int *minor,
 	    unsigned int *micro)
 {
   *major = HB_VERSION_MAJOR;
   *minor = HB_VERSION_MINOR;
   *micro = HB_VERSION_MICRO;
 }
 
+/**
+ * hb_version_string:
+ *
+ * Returns library version as a string with three components.
+ *
+ * Return value: library version string.
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_version_string (void)
 {
   return HB_VERSION_STRING;
 }
 
+/**
+ * hb_version_check:
+ * @major: 
+ * @minor: 
+ * @micro: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_version_check (unsigned int major,
 		  unsigned int minor,
 		  unsigned int micro)
 {
   return HB_VERSION_CHECK (major, minor, micro);
 }
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -126,17 +126,17 @@ hb_direction_to_string (hb_direction_t d
 #define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 4)
 #define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 5)
 #define HB_DIRECTION_IS_VALID(dir)	((((unsigned int) (dir)) & ~3U) == 4)
 #define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */
 
 
 /* hb_language_t */
 
-typedef struct hb_language_impl_t *hb_language_t;
+typedef const struct hb_language_impl_t *hb_language_t;
 
 /* len=-1 means str is NUL-terminated */
 hb_language_t
 hb_language_from_string (const char *str, int len);
 
 const char *
 hb_language_to_string (hb_language_t language);
 
@@ -148,146 +148,162 @@ hb_language_get_default (void);
 
 /* hb_script_t */
 
 /* http://unicode.org/iso15924/ */
 /* http://goo.gl/x9ilM */
 /* Unicode Character Database property: Script (sc) */
 typedef enum
 {
-  /* Unicode-1.1 additions */
-  HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
-  HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
-  HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'),
-  HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'),
-  HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'),
-  HB_SCRIPT_CANADIAN_ABORIGINAL		= HB_TAG ('C','a','n','s'),
-  HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'),
-  HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'),
-  HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'),
-  HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'),
-  HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'),
-  HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'),
-  HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'),
-  HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'),
-  HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'),
-  HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'),
-  HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'),
-  HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'),
-  HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
-  HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'),
-  HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'),
-  HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'),
-  HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'),
-  HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'),
-  HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'),
-  HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'),
-  HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'),
-  HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'),
-  HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'),
-  HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'),
-  HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'),
-  HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'),
-  HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'),
+  /*1.1*/ HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
+  /*1.1*/ HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
+  /*5.0*/ HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),
+
+  /*1.1*/ HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
+  /*1.1*/ HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'),
+  /*1.1*/ HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'),
+  /*1.1*/ HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'),
+  /*1.1*/ HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'),
+  /*1.1*/ HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'),
+  /*1.1*/ HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'),
+  /*1.1*/ HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'),
+  /*1.1*/ HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'),
+  /*1.1*/ HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'),
+  /*1.1*/ HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'),
+  /*1.1*/ HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'),
+  /*1.1*/ HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'),
+  /*1.1*/ HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'),
+  /*1.1*/ HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'),
+  /*1.1*/ HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'),
+  /*1.1*/ HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'),
+  /*1.1*/ HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'),
+  /*1.1*/ HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'),
+  /*1.1*/ HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'),
+  /*1.1*/ HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'),
+  /*1.1*/ HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'),
+
+  /*2.0*/ HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'),
 
-  /* Unicode-2.0 additions */
-  HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'),
+  /*3.0*/ HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'),
+  /*3.0*/ HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'),
+  /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS		= HB_TAG ('C','a','n','s'),
+  /*3.0*/ HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'),
+  /*3.0*/ HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'),
+  /*3.0*/ HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'),
+  /*3.0*/ HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'),
+  /*3.0*/ HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'),
+  /*3.0*/ HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'),
+  /*3.0*/ HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'),
+  /*3.0*/ HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'),
+  /*3.0*/ HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'),
+  /*3.0*/ HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'),
+  /*3.0*/ HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'),
 
-  /* Unicode-3.0 additions */
-  HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'),
-  HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'),
-  HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'),
-  HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'),
-  HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'),
+  /*3.1*/ HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'),
+  /*3.1*/ HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'),
+  /*3.1*/ HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'),
 
-  /* Unicode-3.1 additions */
-  HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'),
-  HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'),
-  HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'),
+  /*3.2*/ HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'),
+  /*3.2*/ HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'),
+  /*3.2*/ HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'),
+  /*3.2*/ HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'),
 
-  /* Unicode-3.2 additions */
-  HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'),
-  HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'),
-  HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'),
-  HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'),
+  /*4.0*/ HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'),
+  /*4.0*/ HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'),
+  /*4.0*/ HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'),
+  /*4.0*/ HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'),
+  /*4.0*/ HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'),
+  /*4.0*/ HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'),
+  /*4.0*/ HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'),
+
+  /*4.1*/ HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'),
+  /*4.1*/ HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'),
+  /*4.1*/ HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'),
+  /*4.1*/ HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'),
+  /*4.1*/ HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'),
+  /*4.1*/ HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'),
+  /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'),
+  /*4.1*/ HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'),
 
-  /* Unicode-4.0 additions */
-  HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'),
-  HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'),
-  HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'),
-  HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'),
-  HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'),
-  HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'),
-  HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'),
-  HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'),
+  /*5.0*/ HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'),
+  /*5.0*/ HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'),
+  /*5.0*/ HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'),
+  /*5.0*/ HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'),
+  /*5.0*/ HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'),
+
+  /*5.1*/ HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'),
+  /*5.1*/ HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'),
+  /*5.1*/ HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'),
+  /*5.1*/ HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'),
+  /*5.1*/ HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'),
+  /*5.1*/ HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'),
+  /*5.1*/ HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'),
+  /*5.1*/ HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'),
+  /*5.1*/ HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'),
+  /*5.1*/ HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'),
+  /*5.1*/ HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'),
 
-  /* Unicode-4.1 additions */
-  HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'),
-  HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'),
-  HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'),
-  HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'),
-  HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'),
-  HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'),
-  HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'),
+  /*5.2*/ HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'),
+  /*5.2*/ HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'),
+  /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'),
+  /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'),
+  /*5.2*/ HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'),
+  /*5.2*/ HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'),
+  /*5.2*/ HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'),
+  /*5.2*/ HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'),
+  /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'),
+  /*5.2*/ HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'),
+  /*5.2*/ HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'),
+  /*5.2*/ HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'),
+  /*5.2*/ HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'),
 
-  /* Unicode-5.0 additions */
-  HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'),
-  HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'),
-  HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'),
-  HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'),
-  HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'),
-  HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),
+  /*6.0*/ HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'),
+  /*6.0*/ HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'),
+  /*6.0*/ HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'),
 
-  /* Unicode-5.1 additions */
-  HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'),
-  HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'),
-  HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'),
-  HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'),
-  HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'),
-  HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'),
-  HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'),
-  HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'),
-  HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'),
-  HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'),
-  HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'),
+  /*6.1*/ HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'),
+  /*6.1*/ HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'),
+  /*6.1*/ HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'),
+  /*6.1*/ HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'),
+  /*6.1*/ HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'),
+
+  /* No script set. */
+  /*---*/ HB_SCRIPT_INVALID			= HB_TAG_NONE
+} hb_script_t;
 
-  /* Unicode-5.2 additions */
-  HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'),
-  HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'),
-  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'),
-  HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'),
-  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'),
-  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'),
-  HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'),
-  HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'),
-  HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'),
-  HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'),
-  HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'),
-  HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'),
-  HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'),
-  HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'),
-  HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'),
-
-  /* Unicode-6.0 additions */
-  HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'),
-  HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'),
-  HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'),
-
-  /* Unicode-6.1 additions */
-  HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'),
-  HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'),
-  HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'),
-  HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'),
-  HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'),
-  HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'),
-  HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'),
-
-  /* No script set */
-  HB_SCRIPT_INVALID			= HB_TAG_NONE
-} hb_script_t;
+/* These are moved out of hb_script_t because glib-mkenums chokes otherwise. */
+#if 0
+  /*7.0*/ HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'),
+  /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'),
+  /*7.0*/ HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'),
+  /*7.0*/ HB_SCRIPT_ELBASAN			= HB_TAG ('E','l','b','a'),
+  /*7.0*/ HB_SCRIPT_GRANTHA			= HB_TAG ('G','r','a','n'),
+  /*7.0*/ HB_SCRIPT_KHOJKI			= HB_TAG ('K','h','o','j'),
+  /*7.0*/ HB_SCRIPT_KHUDAWADI			= HB_TAG ('S','i','n','d'),
+  /*7.0*/ HB_SCRIPT_LINEAR_A			= HB_TAG ('L','i','n','a'),
+  /*7.0*/ HB_SCRIPT_MAHAJANI			= HB_TAG ('M','a','h','j'),
+  /*7.0*/ HB_SCRIPT_MANICHAEAN			= HB_TAG ('M','a','n','i'),
+  /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI		= HB_TAG ('M','e','n','d'),
+  /*7.0*/ HB_SCRIPT_MODI			= ???
+  /*7.0*/ HB_SCRIPT_MRO				= HB_TAG ('M','r','o','o'),
+  /*7.0*/ HB_SCRIPT_NABATAEAN			= HB_TAG ('N','b','a','t'),
+  /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN		= HB_TAG ('N','a','r','b'),
+  /*7.0*/ HB_SCRIPT_OLD_PERMIC			= HB_TAG ('P','e','r','m'),
+  /*7.0*/ HB_SCRIPT_PAHAWH_HMONG		= HB_TAG ('H','m','n','g'),
+  /*7.0*/ HB_SCRIPT_PALMYRENE			= HB_TAG ('P','a','l','m'),
+  /*7.0*/ HB_SCRIPT_PAU_CIN_HAU			= ???
+  /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI		= HB_TAG ('P','h','l','p'),
+  /*7.0*/ HB_SCRIPT_SIDDHAM			= ???
+  /*7.0*/ HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'),
+  /*7.0*/ HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'),
+#endif
 
 
 /* Script functions */
 
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
 /* suger for tag_from_string() then script_from_iso15924_tag */
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -1,11 +1,11 @@
 /*
- * Copyright © 2012  Mozilla Foundation.
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2012,2013  Mozilla Foundation.
+ * Copyright © 2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -165,27 +165,392 @@ hb_coretext_font_get_ct_font (hb_font_t 
   return font_data->ct_font;
 }
 
 
 /*
  * shaper
  */
 
+struct feature_record_t {
+  unsigned int feature;
+  unsigned int setting;
+};
+
+struct active_feature_t {
+  feature_record_t rec;
+  unsigned int order;
+
+  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
+	   a->order < b->order ? -1 : a->order > b->order ? 1 :
+	   a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
+	   0;
+  }
+  bool operator== (const active_feature_t *f) {
+    return cmp (this, f) == 0;
+  }
+};
+
+struct feature_event_t {
+  unsigned int index;
+  bool start;
+  active_feature_t feature;
+
+  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+    return a->index < b->index ? -1 : a->index > b->index ? 1 :
+	   a->start < b->start ? -1 : a->start > b->start ? 1 :
+	   active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct range_record_t {
+  CTFontRef font;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+
+/* The following enum members are added in OS X 10.8. */
+#define kAltHalfWidthTextSelector		6
+#define kAltProportionalTextSelector		5
+#define kAlternateHorizKanaOffSelector		1
+#define kAlternateHorizKanaOnSelector		0
+#define kAlternateKanaType			34
+#define kAlternateVertKanaOffSelector		3
+#define kAlternateVertKanaOnSelector		2
+#define kCaseSensitiveLayoutOffSelector		1
+#define kCaseSensitiveLayoutOnSelector		0
+#define kCaseSensitiveLayoutType		33
+#define kCaseSensitiveSpacingOffSelector	3
+#define kCaseSensitiveSpacingOnSelector		2
+#define kContextualAlternatesOffSelector	1
+#define kContextualAlternatesOnSelector		0
+#define kContextualAlternatesType		36
+#define kContextualLigaturesOffSelector		19
+#define kContextualLigaturesOnSelector		18
+#define kContextualSwashAlternatesOffSelector	5
+#define kContextualSwashAlternatesOnSelector	4
+#define kDefaultLowerCaseSelector		0
+#define kDefaultUpperCaseSelector		0
+#define kHistoricalLigaturesOffSelector		21
+#define kHistoricalLigaturesOnSelector		20
+#define kHojoCharactersSelector			12
+#define kJIS2004CharactersSelector		11
+#define kLowerCasePetiteCapsSelector		2
+#define kLowerCaseSmallCapsSelector		1
+#define kLowerCaseType				37
+#define kMathematicalGreekOffSelector		11
+#define kMathematicalGreekOnSelector		10
+#define kNLCCharactersSelector			13
+#define kQuarterWidthTextSelector		4
+#define kScientificInferiorsSelector		4
+#define kStylisticAltEightOffSelector		17
+#define kStylisticAltEightOnSelector		16
+#define kStylisticAltEighteenOffSelector	37
+#define kStylisticAltEighteenOnSelector		36
+#define kStylisticAltElevenOffSelector		23
+#define kStylisticAltElevenOnSelector		22
+#define kStylisticAltFifteenOffSelector		31
+#define kStylisticAltFifteenOnSelector		30
+#define kStylisticAltFiveOffSelector		11
+#define kStylisticAltFiveOnSelector		10
+#define kStylisticAltFourOffSelector		9
+#define kStylisticAltFourOnSelector		8
+#define kStylisticAltFourteenOffSelector	29
+#define kStylisticAltFourteenOnSelector		28
+#define kStylisticAltNineOffSelector		19
+#define kStylisticAltNineOnSelector		18
+#define kStylisticAltNineteenOffSelector	39
+#define kStylisticAltNineteenOnSelector		38
+#define kStylisticAltOneOffSelector		3
+#define kStylisticAltOneOnSelector		2
+#define kStylisticAltSevenOffSelector		15
+#define kStylisticAltSevenOnSelector		14
+#define kStylisticAltSeventeenOffSelector	35
+#define kStylisticAltSeventeenOnSelector	34
+#define kStylisticAltSixOffSelector		13
+#define kStylisticAltSixOnSelector		12
+#define kStylisticAltSixteenOffSelector		33
+#define kStylisticAltSixteenOnSelector		32
+#define kStylisticAltTenOffSelector		21
+#define kStylisticAltTenOnSelector		20
+#define kStylisticAltThirteenOffSelector	27
+#define kStylisticAltThirteenOnSelector		26
+#define kStylisticAltThreeOffSelector		7
+#define kStylisticAltThreeOnSelector		6
+#define kStylisticAltTwelveOffSelector		25
+#define kStylisticAltTwelveOnSelector		24
+#define kStylisticAltTwentyOffSelector		41
+#define kStylisticAltTwentyOnSelector		40
+#define kStylisticAltTwoOffSelector		5
+#define kStylisticAltTwoOnSelector		4
+#define kStylisticAlternativesType		35
+#define kSwashAlternatesOffSelector		3
+#define kSwashAlternatesOnSelector		2
+#define kThirdWidthTextSelector			3
+#define kTraditionalNamesCharactersSelector	14
+#define kUpperCasePetiteCapsSelector		2
+#define kUpperCaseSmallCapsSelector		1
+#define kUpperCaseType				38
+
+/* Table data courtesy of Apple. */
+struct feature_mapping_t {
+    FourCharCode otFeatureTag;
+    uint16_t aatFeatureType;
+    uint16_t selectorToEnable;
+    uint16_t selectorToDisable;
+} feature_mappings[] = {
+    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
+    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
+    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
+    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
+    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
+    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
+    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
+    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
+    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
+    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
+    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
+    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
+    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
+    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
+    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
+    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
+    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
+    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
+    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
+    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
+    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
+    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
+    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
+    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
+    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
+    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
+    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
+    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
+    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
+    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
+    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
+    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
+    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
+    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
+    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
+    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
+    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
+    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
+    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
+    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
+    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
+    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
+    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
+    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
+    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
+    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
+    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
+    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
+    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
+    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
+    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
+    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
+    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
+    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
+    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
+    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
+    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
+    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
+    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
+    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
+    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
+    { 'unic',   kLetterCaseType,            14,                                     15 },
+    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
+    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
+};
+
+static int
+_hb_feature_mapping_cmp (const void *key_, const void *entry_)
+{
+  unsigned int key = * (unsigned int *) key_;
+  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
+  return key < entry->otFeatureTag ? -1 :
+	 key > entry->otFeatureTag ? 1 :
+	 0;
+}
+
 hb_bool_t
 _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 		    hb_font_t          *font,
                     hb_buffer_t        *buffer,
                     const hb_feature_t *features,
                     unsigned int        num_features)
 {
   hb_face_t *face = font->face;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
 
+  /*
+   * Set up features.
+   * (copied + modified from code from hb-uniscribe.cc)
+   */
+  hb_auto_array_t<feature_record_t> feature_records;
+  hb_auto_array_t<range_record_t> range_records;
+  if (num_features)
+  {
+    /* Sort features by start/end events. */
+    hb_auto_array_t<feature_event_t> feature_events;
+    for (unsigned int i = 0; i < num_features; i++)
+    {
+      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
+									       feature_mappings,
+									       ARRAY_LENGTH (feature_mappings),
+									       sizeof (feature_mappings[0]),
+									       _hb_feature_mapping_cmp);
+      if (!mapping)
+        continue;
+
+      active_feature_t feature;
+      feature.rec.feature = mapping->aatFeatureType;
+      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+      feature.order = i;
+
+      feature_event_t *event;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+	goto fail_features;
+      event->index = features[i].start;
+      event->start = true;
+      event->feature = feature;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+	goto fail_features;
+      event->index = features[i].end;
+      event->start = false;
+      event->feature = feature;
+    }
+    feature_events.sort ();
+    /* Add a strategic final event. */
+    {
+      active_feature_t feature;
+      feature.rec.feature = HB_TAG_NONE;
+      feature.rec.setting = 0;
+      feature.order = num_features + 1;
+
+      feature_event_t *event = feature_events.push ();
+      if (unlikely (!event))
+	goto fail_features;
+      event->index = 0; /* This value does magic. */
+      event->start = false;
+      event->feature = feature;
+    }
+
+    /* Scan events and save features for each range. */
+    hb_auto_array_t<active_feature_t> active_features;
+    unsigned int last_index = 0;
+    for (unsigned int i = 0; i < feature_events.len; i++)
+    {
+      feature_event_t *event = &feature_events[i];
+
+      if (event->index != last_index)
+      {
+        /* Save a snapshot of active features and the range. */
+	range_record_t *range = range_records.push ();
+	if (unlikely (!range))
+	  goto fail_features;
+
+	unsigned int offset = feature_records.len;
+
+	if (active_features.len)
+	{
+	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+	  /* TODO sort and resolve conflicting features? */
+	  /* active_features.sort (); */
+	  for (unsigned int j = 0; j < active_features.len; j++)
+	  {
+	    CFStringRef keys[2] = {
+	      kCTFontFeatureTypeIdentifierKey,
+	      kCTFontFeatureSelectorIdentifierKey
+	    };
+	    CFNumberRef values[2] = {
+	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
+	      CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+	    };
+	    CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
+						       (const void **) keys,
+						       (const void **) values,
+						       2,
+						       &kCFTypeDictionaryKeyCallBacks,
+						       &kCFTypeDictionaryValueCallBacks);
+	    CFRelease (values[0]);
+	    CFRelease (values[1]);
+
+	    CFArrayAppendValue (features_array, dict);
+	    CFRelease (dict);
+
+	  }
+
+	  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+							   (const void **) &kCTFontFeatureSettingsAttribute,
+							   (const void **) &features_array,
+							   1,
+							   &kCFTypeDictionaryKeyCallBacks,
+							   &kCFTypeDictionaryValueCallBacks);
+	  CFRelease (features_array);
+
+	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+	  CFRelease (attributes);
+
+	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+
+	  CFRelease (font_desc);
+	}
+	else
+	{
+	  range->font = NULL;
+	}
+
+	range->index_first = last_index;
+	range->index_last  = event->index - 1;
+
+	last_index = event->index;
+      }
+
+      if (event->start) {
+        active_feature_t *feature = active_features.push ();
+	if (unlikely (!feature))
+	  goto fail_features;
+	*feature = event->feature;
+      } else {
+        active_feature_t *feature = active_features.find (&event->feature);
+	if (feature)
+	  active_features.remove (feature - active_features.array);
+      }
+    }
+
+    if (!range_records.len) /* No active feature found. */
+      goto fail_features;
+  }
+  else
+  {
+  fail_features:
+    num_features = 0;
+  }
+
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
   unsigned int scratch_size;
   char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
@@ -204,40 +569,76 @@ hb_bool_t
     else {
       pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
       pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
     }
   }
 
 #undef utf16_index
 
-  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (kCFAllocatorDefault,
+  CFStringRef string_ref = CFStringCreateWithCharactersNoCopy (NULL,
                                                                pchars, chars_len,
                                                                kCFAllocatorNull);
 
-  CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault,
-                                              (const void**) &kCTFontAttributeName,
-                                              (const void**) &font_data->ct_font,
-                                              1, /* count of attributes */
-                                              &kCFTypeDictionaryKeyCallBacks,
-                                              &kCFTypeDictionaryValueCallBacks);
+  CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
+  CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
+  CFRelease (string_ref);
+  CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+				  kCTFontAttributeName, font_data->ct_font);
+
+  if (num_features)
+  {
+    unsigned int *log_clusters = (unsigned int *) (pchars + chars_len);
+
+    /* Need log_clusters to assign features. */
+    chars_len = 0;
+    for (unsigned int i = 0; i < buffer->len; i++)
+    {
+      hb_codepoint_t c = buffer->info[i].codepoint;
+      unsigned int cluster = buffer->info[i].cluster;
+      log_clusters[chars_len++] = cluster;
+      if (c >= 0x10000 && c < 0x110000)
+	log_clusters[chars_len++] = cluster; /* Surrogates. */
+    }
 
-  /* TODO: support features */
+    unsigned int start = 0;
+    range_record_t *last_range = &range_records[0];
+    for (unsigned int k = 0; k < chars_len; k++)
+    {
+      range_record_t *range = last_range;
+      while (log_clusters[k] < range->index_first)
+	range--;
+      while (log_clusters[k] > range->index_last)
+	range++;
+      if (range != last_range)
+      {
+        if (last_range->font)
+	  CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
+					  kCTFontAttributeName, last_range->font);
 
-  CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs);
-  CFRelease (string_ref);
-  CFRelease (attrs);
+	start = k;
+      }
+
+      last_range = range;
+    }
+    if (start != chars_len && last_range->font)
+      CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start - 1),
+				      kCTFontAttributeName, last_range->font);
+
+    for (unsigned int i = 0; i < range_records.len; i++)
+      if (range_records[i].font)
+	CFRelease (range_records[i].font);
+  }
 
   CTLineRef line = CTLineCreateWithAttributedString (attr_string);
   CFRelease (attr_string);
 
   CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
   unsigned int num_runs = CFArrayGetCount (glyph_runs);
 
-  bool success = true;
   buffer->len = 0;
 
   const CFRange range_all = CFRangeMake (0, 0);
 
   for (unsigned int i = 0; i < num_runs; i++) {
     CTRunRef run = (CTRunRef) CFArrayGetValueAtIndex (glyph_runs, i);
 
     unsigned int num_glyphs = CTRunGetGlyphCount (run);
@@ -282,17 +683,16 @@ hb_bool_t
 #undef ALLOCATE_ARRAY
 
     double run_width = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
 
     for (unsigned int j = 0; j < num_glyphs; j++) {
       double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_width) - positions[j].x;
 
       hb_glyph_info_t *info = &buffer->info[buffer->len];
-      hb_glyph_position_t *pos = &buffer->pos[buffer->len];
 
       info->codepoint = glyphs[j];
       info->cluster = string_indices[j];
 
       /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */
       info->mask = advance;
       info->var1.u32 = 0;
       info->var2.u32 = positions[j].y;
@@ -346,10 +746,12 @@ hb_bool_t
           else
             break;
         }
       }
       prev_cluster = curr_cluster;
     }
   }
 
+  CFRelease (line);
+
   return true;
 }
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-deprecated.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_DEPRECATED_H
+#define HB_DEPRECATED_H
+
+#include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+#ifndef HB_DISABLE_DEPRECATED
+
+#define HB_SCRIPT_CANADIAN_ABORIGINAL		HB_SCRIPT_CANADIAN_SYLLABICS
+
+#define HB_BUFFER_FLAGS_DEFAULT			HB_BUFFER_FLAG_DEFAULT
+#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT	HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+
+#endif
+
+HB_END_DECLS
+
+#endif /* HB_DEPRECATED_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-face-private.hh
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2011  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_FACE_PRIVATE_HH
+#define HB_FACE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-font.h"
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+
+
+/*
+ * hb_face_t
+ */
+
+struct hb_face_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t immutable;
+
+  hb_reference_table_func_t  reference_table_func;
+  void                      *user_data;
+  hb_destroy_func_t          destroy;
+
+  unsigned int index;
+  mutable unsigned int upem;
+  mutable unsigned int num_glyphs;
+
+  struct hb_shaper_data_t shaper_data;
+
+  struct plan_node_t {
+    hb_shape_plan_t *shape_plan;
+    plan_node_t *next;
+  } *shape_plans;
+
+
+  inline hb_blob_t *reference_table (hb_tag_t tag) const
+  {
+    hb_blob_t *blob;
+
+    if (unlikely (!this || !reference_table_func))
+      return hb_blob_get_empty ();
+
+    blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+    if (unlikely (!blob))
+      return hb_blob_get_empty ();
+
+    return blob;
+  }
+
+  inline HB_PURE_FUNC unsigned int get_upem (void) const
+  {
+    if (unlikely (!upem))
+      load_upem ();
+    return upem;
+  }
+
+  inline unsigned int get_num_glyphs (void) const
+  {
+    if (unlikely (num_glyphs == (unsigned int) -1))
+      load_num_glyphs ();
+    return num_glyphs;
+  }
+
+  private:
+  HB_INTERNAL void load_upem (void) const;
+  HB_INTERNAL void load_num_glyphs (void) const;
+};
+
+extern HB_INTERNAL const hb_face_t _hb_face_nil;
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_FACE_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-face.cc
@@ -0,0 +1,482 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-blob.h"
+#include "hb-open-file-private.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
+
+#include "hb-cache-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_face_t
+ */
+
+const hb_face_t _hb_face_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  NULL, /* reference_table_func */
+  NULL, /* user_data */
+  NULL, /* destroy */
+
+  0,    /* index */
+  1000, /* upem */
+  0,    /* num_glyphs */
+
+  {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  },
+
+  NULL, /* shape_plans */
+};
+
+
+/**
+ * hb_face_create_for_tables:
+ * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data: 
+ * @destroy: 
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+			   void                      *user_data,
+			   hb_destroy_func_t          destroy)
+{
+  hb_face_t *face;
+
+  if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
+    if (destroy)
+      destroy (user_data);
+    return hb_face_get_empty ();
+  }
+
+  face->reference_table_func = reference_table_func;
+  face->user_data = user_data;
+  face->destroy = destroy;
+
+  face->upem = 0;
+  face->num_glyphs = (unsigned int) -1;
+
+  return face;
+}
+
+
+typedef struct hb_face_for_data_closure_t {
+  hb_blob_t *blob;
+  unsigned int  index;
+} hb_face_for_data_closure_t;
+
+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 = blob;
+  closure->index = index;
+
+  return closure;
+}
+
+static void
+_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
+{
+  hb_blob_destroy (closure->blob);
+  free (closure);
+}
+
+static hb_blob_t *
+_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+  if (tag == HB_TAG_NONE)
+    return hb_blob_reference (data->blob);
+
+  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+  const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
+
+  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
+
+  return blob;
+}
+
+/**
+ * hb_face_create: (Xconstructor)
+ * @blob: 
+ * @index: 
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+		unsigned int  index)
+{
+  hb_face_t *face;
+
+  if (unlikely (!blob || !hb_blob_get_length (blob)))
+    return hb_face_get_empty ();
+
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+
+  if (unlikely (!closure))
+    return hb_face_get_empty ();
+
+  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
+				    closure,
+				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_face_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_get_empty (void)
+{
+  return const_cast<hb_face_t *> (&_hb_face_nil);
+}
+
+
+/**
+ * hb_face_reference: (skip)
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_reference (hb_face_t *face)
+{
+  return hb_object_reference (face);
+}
+
+/**
+ * hb_face_destroy: (skip)
+ * @face: a face.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_destroy (hb_face_t *face)
+{
+  if (!hb_object_destroy (face)) return;
+
+  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+  {
+    hb_face_t::plan_node_t *next = node->next;
+    hb_shape_plan_destroy (node->shape_plan);
+    free (node);
+    node = next;
+  }
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (face->destroy)
+    face->destroy (face->user_data);
+
+  free (face);
+}
+
+/**
+ * hb_face_set_user_data: (skip)
+ * @face: a face.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+		       hb_user_data_key_t *key,
+		       void *              data,
+		       hb_destroy_func_t   destroy,
+		       hb_bool_t           replace)
+{
+  return hb_object_set_user_data (face, key, data, destroy, replace);
+}
+
+/**
+ * hb_face_get_user_data: (skip)
+ * @face: a face.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+void *
+hb_face_get_user_data (hb_face_t          *face,
+		       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (face, key);
+}
+
+/**
+ * hb_face_make_immutable:
+ * @face: a face.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_make_immutable (hb_face_t *face)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->immutable = true;
+}
+
+/**
+ * hb_face_is_immutable:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face)
+{
+  return face->immutable;
+}
+
+
+/**
+ * hb_face_reference_table:
+ * @face: a face.
+ * @tag: 
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+			 hb_tag_t   tag)
+{
+  return face->reference_table (tag);
+}
+
+/**
+ * hb_face_reference_blob:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face)
+{
+  return face->reference_table (HB_TAG_NONE);
+}
+
+/**
+ * hb_face_set_index:
+ * @face: a face.
+ * @index: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_index (hb_face_t    *face,
+		   unsigned int  index)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->index = index;
+}
+
+/**
+ * hb_face_get_index:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_index (hb_face_t    *face)
+{
+  return face->index;
+}
+
+/**
+ * hb_face_set_upem:
+ * @face: a face.
+ * @upem: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_upem (hb_face_t    *face,
+		  unsigned int  upem)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->upem = upem;
+}
+
+/**
+ * hb_face_get_upem:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_upem (hb_face_t *face)
+{
+  return face->get_upem ();
+}
+
+void
+hb_face_t::load_upem (void) const
+{
+  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+  const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+  upem = head_table->get_upem ();
+  hb_blob_destroy (head_blob);
+}
+
+/**
+ * hb_face_set_glyph_count:
+ * @face: a face.
+ * @glyph_count: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+			 unsigned int  glyph_count)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->num_glyphs = glyph_count;
+}
+
+/**
+ * hb_face_get_glyph_count:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face)
+{
+  return face->get_num_glyphs ();
+}
+
+void
+hb_face_t::load_num_glyphs (void) const
+{
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+  num_glyphs = maxp_table->get_num_glyphs ();
+  hb_blob_destroy (maxp_blob);
+}
+
+
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-face.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_FACE_H
+#define HB_FACE_H
+
+#include "hb-common.h"
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_face_t
+ */
+
+typedef struct hb_face_t hb_face_t;
+
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+		unsigned int  index);
+
+typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
+
+/* calls destroy() when not needing user_data anymore */
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+			   void                      *user_data,
+			   hb_destroy_func_t          destroy);
+
+hb_face_t *
+hb_face_get_empty (void);
+
+hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+void
+hb_face_destroy (hb_face_t *face);
+
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+		       hb_user_data_key_t *key,
+		       void *              data,
+		       hb_destroy_func_t   destroy,
+		       hb_bool_t           replace);
+
+
+void *
+hb_face_get_user_data (hb_face_t          *face,
+		       hb_user_data_key_t *key);
+
+void
+hb_face_make_immutable (hb_face_t *face);
+
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face);
+
+
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+			 hb_tag_t   tag);
+
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face);
+
+void
+hb_face_set_index (hb_face_t    *face,
+		   unsigned int  index);
+
+unsigned int
+hb_face_get_index (hb_face_t    *face);
+
+void
+hb_face_set_upem (hb_face_t    *face,
+		  unsigned int  upem);
+
+unsigned int
+hb_face_get_upem (hb_face_t *face);
+
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+			 unsigned int  glyph_count);
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
+
+HB_END_DECLS
+
+#endif /* HB_FACE_H */
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -28,18 +28,18 @@
 
 #ifndef HB_FONT_PRIVATE_HH
 #define HB_FONT_PRIVATE_HH
 
 #include "hb-private.hh"
 
 #include "hb-font.h"
 #include "hb-object-private.hh"
+#include "hb-face-private.hh"
 #include "hb-shaper-private.hh"
-#include "hb-shape-plan-private.hh"
 
 
 
 /*
  * hb_font_funcs_t
  */
 
 #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
@@ -79,81 +79,16 @@ struct hb_font_funcs_t {
   struct {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   } destroy;
 };
 
 
-/*
- * hb_face_t
- */
-
-struct hb_face_t {
-  hb_object_header_t header;
-  ASSERT_POD ();
-
-  hb_bool_t immutable;
-
-  hb_reference_table_func_t  reference_table_func;
-  void                      *user_data;
-  hb_destroy_func_t          destroy;
-
-  unsigned int index;
-  mutable unsigned int upem;
-  mutable unsigned int num_glyphs;
-
-  struct hb_shaper_data_t shaper_data;
-
-  struct plan_node_t {
-    hb_shape_plan_t *shape_plan;
-    plan_node_t *next;
-  } *shape_plans;
-
-
-  inline hb_blob_t *reference_table (hb_tag_t tag) const
-  {
-    hb_blob_t *blob;
-
-    if (unlikely (!this || !reference_table_func))
-      return hb_blob_get_empty ();
-
-    blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
-    if (unlikely (!blob))
-      return hb_blob_get_empty ();
-
-    return blob;
-  }
-
-  inline unsigned int get_upem (void) const
-  {
-    if (unlikely (!upem))
-      load_upem ();
-    return upem;
-  }
-
-  inline unsigned int get_num_glyphs (void) const
-  {
-    if (unlikely (num_glyphs == (unsigned int) -1))
-      load_num_glyphs ();
-    return num_glyphs;
-  }
-
-  private:
-  HB_INTERNAL void load_upem (void) const;
-  HB_INTERNAL void load_num_glyphs (void) const;
-};
-
-#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
-#include "hb-shaper-list.hh"
-#undef HB_SHAPER_IMPLEMENT
-#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
-
 
 /*
  * hb_font_t
  */
 
 struct hb_font_t {
   hb_object_header_t header;
   ASSERT_POD ();
@@ -253,20 +188,20 @@ struct hb_font_t {
 
   inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
   {
     return klass->get.glyph_h_kerning (this, user_data,
 				       left_glyph, right_glyph,
 				       klass->user_data.glyph_h_kerning);
   }
 
-  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
   {
     return klass->get.glyph_v_kerning (this, user_data,
-				       left_glyph, right_glyph,
+				       top_glyph, bottom_glyph,
 				       klass->user_data.glyph_v_kerning);
   }
 
   inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
 				      hb_glyph_extents_t *extents)
   {
     memset (extents, 0, sizeof (*extents));
     return klass->get.glyph_extents (this, user_data,
@@ -331,26 +266,31 @@ struct hb_font_t {
     /* TODO use font_metics.ascent */
     *y = y_scale;
   }
 
   inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
 					      hb_direction_t direction,
 					      hb_position_t *x, hb_position_t *y)
   {
-    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-      hb_bool_t ret = get_glyph_h_origin (glyph, x, y);
-      if (!ret && (ret = get_glyph_v_origin (glyph, x, y))) {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+    {
+      if (!get_glyph_h_origin (glyph, x, y) &&
+	   get_glyph_v_origin (glyph, x, y))
+      {
 	hb_position_t dx, dy;
 	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
 	*x -= dx; *y -= dy;
       }
-    } else {
-      hb_bool_t ret = get_glyph_v_origin (glyph, x, y);
-      if (!ret && (ret = get_glyph_h_origin (glyph, x, y))) {
+    }
+    else
+    {
+      if (!get_glyph_v_origin (glyph, x, y) &&
+	   get_glyph_h_origin (glyph, x, y))
+      {
 	hb_position_t dx, dy;
 	guess_v_origin_minus_h_origin (glyph, &dx, &dy);
 	*x += dx; *y += dy;
       }
     }
   }
 
   inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
@@ -416,17 +356,18 @@ struct hb_font_t {
 
   /* Generates gidDDD if glyph has no name. */
   inline void
   glyph_to_string (hb_codepoint_t glyph,
 		   char *s, unsigned int size)
   {
     if (get_glyph_name (glyph, s, size)) return;
 
-    snprintf (s, size, "gid%u", glyph);
+    if (size && snprintf (s, size, "gid%u", glyph) < 0)
+      *s = '\0';
   }
 
   /* Parses gidDDD and uniUUUU strings automatically. */
   inline hb_bool_t
   glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
 		     hb_codepoint_t *glyph)
   {
     if (get_glyph_from_name (s, len, glyph)) return true;
@@ -451,17 +392,17 @@ struct hb_font_t {
 	  get_glyph (unichar, 0, glyph))
 	return true;
     }
 
     return false;
   }
 
   private:
-  inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
+  inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / face->get_upem (); }
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 #undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -36,17 +36,16 @@
 #include "hb-ot-head-table.hh"
 #include "hb-ot-maxp-table.hh"
 
 #include "hb-cache-private.hh"
 
 #include <string.h>
 
 
-
 /*
  * hb_font_funcs_t
  */
 
 static hb_bool_t
 hb_font_get_glyph_nil (hb_font_t *font,
 		       void *font_data HB_UNUSED,
 		       hb_codepoint_t unicode,
@@ -226,81 +225,160 @@ static const hb_font_funcs_t _hb_font_fu
   {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
     HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
   }
 };
 
 
+/**
+ * hb_font_funcs_create: (Xconstructor)
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_create (void)
 {
   hb_font_funcs_t *ffuncs;
 
   if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
     return hb_font_funcs_get_empty ();
 
   ffuncs->get = _hb_font_funcs_nil.get;
 
   return ffuncs;
 }
 
+/**
+ * hb_font_funcs_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_get_empty (void)
 {
   return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
 }
 
+/**
+ * hb_font_funcs_reference: (skip)
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
 {
   return hb_object_reference (ffuncs);
 }
 
+/**
+ * hb_font_funcs_destroy: (skip)
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
 {
   if (!hb_object_destroy (ffuncs)) return;
 
 #define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \
   ffuncs->destroy.name (ffuncs->user_data.name);
   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
   free (ffuncs);
 }
 
+/**
+ * hb_font_funcs_set_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
 			     hb_user_data_key_t *key,
 			     void *              data,
 			     hb_destroy_func_t   destroy,
 			     hb_bool_t           replace)
 {
   return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
 }
 
+/**
+ * hb_font_funcs_get_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
 			     hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (ffuncs, key);
 }
 
 
+/**
+ * hb_font_funcs_make_immutable:
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
 {
   if (hb_object_is_inert (ffuncs))
     return;
 
   ffuncs->immutable = true;
 }
 
+/**
+ * hb_font_funcs_is_immutable:
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
 {
   return ffuncs->immutable;
 }
 
 
 #define HB_FONT_FUNC_IMPLEMENT(name) \
@@ -332,457 +410,449 @@ hb_font_funcs_set_##name##_func (hb_font
 }
 
 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
 
 /* Public getters */
 
+/**
+ * hb_font_get_glyph:
+ * @font: a font.
+ * @unicode: 
+ * @variation_selector: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
 		   hb_codepoint_t *glyph)
 {
   return font->get_glyph (unicode, variation_selector, glyph);
 }
 
+/**
+ * hb_font_get_glyph_h_advance:
+ * @font: a font.
+ * @glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
 			     hb_codepoint_t glyph)
 {
   return font->get_glyph_h_advance (glyph);
 }
 
+/**
+ * hb_font_get_glyph_v_advance:
+ * @font: a font.
+ * @glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
 			     hb_codepoint_t glyph)
 {
   return font->get_glyph_v_advance (glyph);
 }
 
+/**
+ * hb_font_get_glyph_h_origin:
+ * @font: a font.
+ * @glyph: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_h_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_h_origin (glyph, x, y);
 }
 
+/**
+ * hb_font_get_glyph_v_origin:
+ * @font: a font.
+ * @glyph: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_v_origin (hb_font_t *font,
 			    hb_codepoint_t glyph,
 			    hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_v_origin (glyph, x, y);
 }
 
+/**
+ * hb_font_get_glyph_h_kerning:
+ * @font: a font.
+ * @left_glyph: 
+ * @right_glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
 			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 {
   return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
 
+/**
+ * hb_font_get_glyph_v_kerning:
+ * @font: a font.
+ * @top_glyph: 
+ * @bottom_glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
-			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+			     hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
 {
-  return font->get_glyph_v_kerning (left_glyph, right_glyph);
+  return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
 }
 
+/**
+ * hb_font_get_glyph_extents:
+ * @font: a font.
+ * @glyph: 
+ * @extents: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
 			   hb_codepoint_t glyph,
 			   hb_glyph_extents_t *extents)
 {
   return font->get_glyph_extents (glyph, extents);
 }
 
+/**
+ * hb_font_get_glyph_contour_point:
+ * @font: a font.
+ * @glyph: 
+ * @point_index: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_contour_point (hb_font_t *font,
 				 hb_codepoint_t glyph, unsigned int point_index,
 				 hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_contour_point (glyph, point_index, x, y);
 }
 
+/**
+ * hb_font_get_glyph_name:
+ * @font: a font.
+ * @glyph: 
+ * @name: (array length=size): 
+ * @size: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_name (hb_font_t *font,
 			hb_codepoint_t glyph,
 			char *name, unsigned int size)
 {
   return font->get_glyph_name (glyph, name, size);
 }
 
+/**
+ * hb_font_get_glyph_from_name:
+ * @font: a font.
+ * @name: (array length=len): 
+ * @len: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
 			     const char *name, int len, /* -1 means nul-terminated */
 			     hb_codepoint_t *glyph)
 {
   return font->get_glyph_from_name (name, len, glyph);
 }
 
 
 /* A bit higher-level, and with fallback */
 
+/**
+ * hb_font_get_glyph_advance_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
 					 hb_codepoint_t glyph,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_get_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
 					hb_codepoint_t glyph,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_add_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_add_glyph_origin_for_direction (hb_font_t *font,
 					hb_codepoint_t glyph,
 					hb_direction_t direction,
 					hb_position_t *x, hb_position_t *y)
 {
   return font->add_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_subtract_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
 					     hb_codepoint_t glyph,
 					     hb_direction_t direction,
 					     hb_position_t *x, hb_position_t *y)
 {
   return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_get_glyph_kerning_for_direction:
+ * @font: a font.
+ * @first_glyph: 
+ * @second_glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
 					 hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
 					 hb_direction_t direction,
 					 hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
 }
 
+/**
+ * hb_font_get_glyph_extents_for_origin:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @extents: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
 				      hb_codepoint_t glyph,
 				      hb_direction_t direction,
 				      hb_glyph_extents_t *extents)
 {
   return font->get_glyph_extents_for_origin (glyph, direction, extents);
 }
 
+/**
+ * hb_font_get_glyph_contour_point_for_origin:
+ * @font: a font.
+ * @glyph: 
+ * @point_index: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
 					    hb_codepoint_t glyph, unsigned int point_index,
 					    hb_direction_t direction,
 					    hb_position_t *x, hb_position_t *y)
 {
   return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
 }
 
 /* Generates gidDDD if glyph has no name. */
+/**
+ * hb_font_glyph_to_string:
+ * @font: a font.
+ * @glyph: 
+ * @s: (array length=size): 
+ * @size: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_glyph_to_string (hb_font_t *font,
 			 hb_codepoint_t glyph,
 			 char *s, unsigned int size)
 {
   font->glyph_to_string (glyph, s, size);
 }
 
 /* Parses gidDDD and uniUUUU strings automatically. */
+/**
+ * hb_font_glyph_from_string:
+ * @font: a font.
+ * @s: (array length=len): 
+ * @len: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_glyph_from_string (hb_font_t *font,
 			   const char *s, int len, /* -1 means nul-terminated */
 			   hb_codepoint_t *glyph)
 {
   return font->glyph_from_string (s, len, glyph);
 }
 
 
 /*
- * hb_face_t
- */
-
-static const hb_face_t _hb_face_nil = {
-  HB_OBJECT_HEADER_STATIC,
-
-  true, /* immutable */
-
-  NULL, /* reference_table_func */
-  NULL, /* user_data */
-  NULL, /* destroy */
-
-  0,    /* index */
-  1000, /* upem */
-  0,    /* num_glyphs */
-
-  {
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
-#include "hb-shaper-list.hh"
-#undef HB_SHAPER_IMPLEMENT
-  },
-
-  NULL, /* shape_plans */
-};
-
-
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
-			   void                      *user_data,
-			   hb_destroy_func_t          destroy)
-{
-  hb_face_t *face;
-
-  if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
-    if (destroy)
-      destroy (user_data);
-    return hb_face_get_empty ();
-  }
-
-  face->reference_table_func = reference_table_func;
-  face->user_data = user_data;
-  face->destroy = destroy;
-
-  face->upem = 0;
-  face->num_glyphs = (unsigned int) -1;
-
-  return face;
-}
-
-
-typedef struct hb_face_for_data_closure_t {
-  hb_blob_t *blob;
-  unsigned int  index;
-} hb_face_for_data_closure_t;
-
-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 = blob;
-  closure->index = index;
-
-  return closure;
-}
-
-static void
-_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
-{
-  hb_blob_destroy (closure->blob);
-  free (closure);
-}
-
-static hb_blob_t *
-_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
-  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
-
-  if (tag == HB_TAG_NONE)
-    return hb_blob_reference (data->blob);
-
-  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
-  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
-
-  const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
-
-  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
-
-  return blob;
-}
-
-hb_face_t *
-hb_face_create (hb_blob_t    *blob,
-		unsigned int  index)
-{
-  hb_face_t *face;
-
-  if (unlikely (!blob || !hb_blob_get_length (blob)))
-    return hb_face_get_empty ();
-
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
-
-  if (unlikely (!closure))
-    return hb_face_get_empty ();
-
-  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
-				    closure,
-				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
-
-  hb_face_set_index (face, index);
-
-  return face;
-}
-
-hb_face_t *
-hb_face_get_empty (void)
-{
-  return const_cast<hb_face_t *> (&_hb_face_nil);
-}
-
-
-hb_face_t *
-hb_face_reference (hb_face_t *face)
-{
-  return hb_object_reference (face);
-}
-
-void
-hb_face_destroy (hb_face_t *face)
-{
-  if (!hb_object_destroy (face)) return;
-
-  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
-  {
-    hb_face_t::plan_node_t *next = node->next;
-    hb_shape_plan_destroy (node->shape_plan);
-    free (node);
-    node = next;
-  }
-
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
-#include "hb-shaper-list.hh"
-#undef HB_SHAPER_IMPLEMENT
-
-  if (face->destroy)
-    face->destroy (face->user_data);
-
-  free (face);
-}
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t          *face,
-		       hb_user_data_key_t *key,
-		       void *              data,
-		       hb_destroy_func_t   destroy,
-		       hb_bool_t           replace)
-{
-  return hb_object_set_user_data (face, key, data, destroy, replace);
-}
-
-void *
-hb_face_get_user_data (hb_face_t          *face,
-		       hb_user_data_key_t *key)
-{
-  return hb_object_get_user_data (face, key);
-}
-
-void
-hb_face_make_immutable (hb_face_t *face)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->immutable = true;
-}
-
-hb_bool_t
-hb_face_is_immutable (hb_face_t *face)
-{
-  return face->immutable;
-}
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
-			 hb_tag_t   tag)
-{
-  return face->reference_table (tag);
-}
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face)
-{
-  return face->reference_table (HB_TAG_NONE);
-}
-
-void
-hb_face_set_index (hb_face_t    *face,
-		   unsigned int  index)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->index = index;
-}
-
-unsigned int
-hb_face_get_index (hb_face_t    *face)
-{
-  return face->index;
-}
-
-void
-hb_face_set_upem (hb_face_t    *face,
-		  unsigned int  upem)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->upem = upem;
-}
-
-unsigned int
-hb_face_get_upem (hb_face_t *face)
-{
-  return face->get_upem ();
-}
-
-void
-hb_face_t::load_upem (void) const
-{
-  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
-  const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
-  upem = head_table->get_upem ();
-  hb_blob_destroy (head_blob);
-}
-
-void
-hb_face_set_glyph_count (hb_face_t    *face,
-			 unsigned int  glyph_count)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->num_glyphs = glyph_count;
-}
-
-unsigned int
-hb_face_get_glyph_count (hb_face_t *face)
-{
-  return face->get_num_glyphs ();
-}
-
-void
-hb_face_t::load_num_glyphs (void) const
-{
-  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
-  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
-  num_glyphs = maxp_table->get_num_glyphs ();
-  hb_blob_destroy (maxp_blob);
-}
-
-
-/*
  * hb_font_t
  */
 
+/**
+ * hb_font_create: (Xconstructor)
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_create (hb_face_t *face)
 {
   hb_font_t *font;
 
   if (unlikely (!face))
     face = hb_face_get_empty ();
   if (unlikely (hb_object_is_inert (face)))
@@ -792,16 +862,26 @@ hb_font_create (hb_face_t *face)
 
   hb_face_make_immutable (face);
   font->face = hb_face_reference (face);
   font->klass = hb_font_funcs_get_empty ();
 
   return font;
 }
 
+/**
+ * hb_font_create_sub_font:
+ * @parent: parent font.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_create_sub_font (hb_font_t *parent)
 {
   if (unlikely (!parent))
     return hb_font_get_empty ();
 
   hb_font_t *font = hb_font_create (parent->face);
 
@@ -814,16 +894,25 @@ hb_font_create_sub_font (hb_font_t *pare
   font->x_scale = parent->x_scale;
   font->y_scale = parent->y_scale;
   font->x_ppem = parent->x_ppem;
   font->y_ppem = parent->y_ppem;
 
   return font;
 }
 
+/**
+ * hb_font_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_get_empty (void)
 {
   static const hb_font_t _hb_font_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* immutable */
 
@@ -845,22 +934,40 @@ hb_font_get_empty (void)
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
     }
   };
 
   return const_cast<hb_font_t *> (&_hb_font_nil);
 }
 
+/**
+ * hb_font_reference: (skip)
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_reference (hb_font_t *font)
 {
   return hb_object_reference (font);
 }
 
+/**
+ * hb_font_destroy: (skip)
+ * @font: a font.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_destroy (hb_font_t *font)
 {
   if (!hb_object_destroy (font)) return;
 
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
@@ -870,139 +977,263 @@ hb_font_destroy (hb_font_t *font)
 
   hb_font_destroy (font->parent);
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
   free (font);
 }
 
+/**
+ * hb_font_set_user_data: (skip)
+ * @font: a font.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_set_user_data (hb_font_t          *font,
 		       hb_user_data_key_t *key,
 		       void *              data,
 		       hb_destroy_func_t   destroy,
 		       hb_bool_t           replace)
 {
   return hb_object_set_user_data (font, key, data, destroy, replace);
 }
 
+/**
+ * hb_font_get_user_data: (skip)
+ * @font: a font.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_font_get_user_data (hb_font_t          *font,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (font, key);
 }
 
+/**
+ * hb_font_make_immutable:
+ * @font: a font.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_make_immutable (hb_font_t *font)
 {
   if (hb_object_is_inert (font))
     return;
 
   font->immutable = true;
 }
 
+/**
+ * hb_font_is_immutable:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_is_immutable (hb_font_t *font)
 {
   return font->immutable;
 }
 
+/**
+ * hb_font_get_parent:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_get_parent (hb_font_t *font)
 {
   return font->parent;
 }
 
+/**
+ * hb_font_get_face:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 hb_face_t *
 hb_font_get_face (hb_font_t *font)
 {
   return font->face;
 }
 
 
+/**
+ * hb_font_set_funcs:
+ * @font: a font.
+ * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @font_data: 
+ * @destroy: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
-		   void              *user_data,
+		   void              *font_data,
 		   hb_destroy_func_t  destroy)
 {
   if (font->immutable) {
     if (destroy)
-      destroy (user_data);
+      destroy (font_data);
     return;
   }
 
   if (font->destroy)
     font->destroy (font->user_data);
 
   if (!klass)
     klass = hb_font_funcs_get_empty ();
 
   hb_font_funcs_reference (klass);
   hb_font_funcs_destroy (font->klass);
   font->klass = klass;
-  font->user_data = user_data;
+  font->user_data = font_data;
   font->destroy = destroy;
 }
 
+/**
+ * hb_font_set_funcs_data:
+ * @font: a font.
+ * @font_data: (destroy destroy) (scope notified):
+ * @destroy: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_funcs_data (hb_font_t         *font,
-		        void              *user_data,
+		        void              *font_data,
 		        hb_destroy_func_t  destroy)
 {
   /* Destroy user_data? */
   if (font->immutable) {
     if (destroy)
-      destroy (user_data);
+      destroy (font_data);
     return;
   }
 
   if (font->destroy)
     font->destroy (font->user_data);
 
-  font->user_data = user_data;
+  font->user_data = font_data;
   font->destroy = destroy;
 }
 
 
+/**
+ * hb_font_set_scale:
+ * @font: a font.
+ * @x_scale: 
+ * @y_scale: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_scale (hb_font_t *font,
 		   int x_scale,
 		   int y_scale)
 {
   if (font->immutable)
     return;
 
   font->x_scale = x_scale;
   font->y_scale = y_scale;
 }
 
+/**
+ * hb_font_get_scale:
+ * @font: a font.
+ * @x_scale: (out): 
+ * @y_scale: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_scale (hb_font_t *font,
 		   int *x_scale,
 		   int *y_scale)
 {
   if (x_scale) *x_scale = font->x_scale;
   if (y_scale) *y_scale = font->y_scale;
 }
 
+/**
+ * hb_font_set_ppem:
+ * @font: a font.
+ * @x_ppem: 
+ * @y_ppem: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem)
 {
   if (font->immutable)
     return;
 
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
 }
 
+/**
+ * hb_font_get_ppem:
+ * @font: a font.
+ * @x_ppem: (out): 
+ * @y_ppem: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 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;
 }
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -27,96 +27,23 @@
 #ifndef HB_H_IN
 #error "Include <hb.h> instead."
 #endif
 
 #ifndef HB_FONT_H
 #define HB_FONT_H
 
 #include "hb-common.h"
-#include "hb-blob.h"
+#include "hb-face.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 *
-hb_face_create (hb_blob_t    *blob,
-		unsigned int  index);
-
-typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
-
-/* calls destroy() when not needing user_data anymore */
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
-			   void                      *user_data,
-			   hb_destroy_func_t          destroy);
-
-hb_face_t *
-hb_face_get_empty (void);
-
-hb_face_t *
-hb_face_reference (hb_face_t *face);
-
-void
-hb_face_destroy (hb_face_t *face);
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t          *face,
-		       hb_user_data_key_t *key,
-		       void *              data,
-		       hb_destroy_func_t   destroy,
-		       hb_bool_t           replace);
-
-
-void *
-hb_face_get_user_data (hb_face_t          *face,
-		       hb_user_data_key_t *key);
-
-void
-hb_face_make_immutable (hb_face_t *face);
-
-hb_bool_t
-hb_face_is_immutable (hb_face_t *face);
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
-			 hb_tag_t   tag);
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face);
-
-void
-hb_face_set_index (hb_face_t    *face,
-		   unsigned int  index);
-
-unsigned int
-hb_face_get_index (hb_face_t    *face);
-
-void
-hb_face_set_upem (hb_face_t    *face,
-		  unsigned int  upem);
-
-unsigned int
-hb_face_get_upem (hb_face_t *face);
-
-void
-hb_face_set_glyph_count (hb_face_t    *face,
-			 unsigned int  glyph_count);
-
-unsigned int
-hb_face_get_glyph_count (hb_face_t *face);
-
 
 /*
  * hb_font_funcs_t
  */
 
 typedef struct hb_font_funcs_t hb_font_funcs_t;
 
 hb_font_funcs_t *
@@ -207,64 +134,190 @@ typedef hb_bool_t (*hb_font_get_glyph_na
 typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
 							 const char *name, int len, /* -1 means nul-terminated */
 							 hb_codepoint_t *glyph,
 							 void *user_data);
 
 
 /* func setters */
 
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
-			      hb_font_get_glyph_func_t glyph_func,
+			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_h_advance_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_v_advance_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
 				       hb_font_get_glyph_h_origin_func_t func,
 				       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
 				       hb_font_get_glyph_v_origin_func_t func,
 				       void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_h_kerning_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
 					hb_font_get_glyph_v_kerning_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
 				      hb_font_get_glyph_extents_func_t func,
 				      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_contour_point_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
 					    hb_font_get_glyph_contour_point_func_t func,
 					    void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
-				   hb_font_get_glyph_name_func_t glyph_func,
+				   hb_font_get_glyph_name_func_t func,
 				   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_from_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
-					hb_font_get_glyph_from_name_func_t glyph_func,
+					hb_font_get_glyph_from_name_func_t func,
 					void *user_data, hb_destroy_func_t destroy);
 
 
 /* func dispatch */
 
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
 		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -68,18 +68,17 @@ hb_ft_get_glyph (hb_font_t *font HB_UNUS
 		 void *user_data HB_UNUSED)
 
 {
   FT_Face ft_face = (FT_Face) font_data;
 
 #ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
   if (unlikely (variation_selector)) {
     *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
-    if (*glyph)
-      return true;
+    return *glyph != 0;
   }
 #endif
 
   *glyph = FT_Get_Char_Index (ft_face, unicode);
   return *glyph != 0;
 }
 
 static hb_position_t
@@ -256,16 +255,25 @@ hb_ft_get_glyph_from_name (hb_font_t *fo
     /* Make a nul-terminated version. */
     char buf[128];
     len = MIN (len, (int) sizeof (buf) - 1);
     strncpy (buf, name, len);
     buf[len] = '\0';
     *glyph = FT_Get_Name_Index (ft_face, buf);
   }
 
+  if (*glyph == 0)
+  {
+    /* Check whether the given name was actually the name of glyph 0. */
+    char buf[128];
+    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
+        len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+      return true;
+  }
+
   return *glyph != 0;
 }
 
 
 static hb_font_funcs_t *
 _hb_ft_get_font_funcs (void)
 {
   static const hb_font_funcs_t ft_ffuncs = {
@@ -306,17 +314,26 @@ reference_table  (hb_face_t *face HB_UNU
   if (error)
     return NULL;
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
 			 buffer, free);
 }
 
-
+/**
+ * hb_ft_face_create:
+ * @ft_face: (destroy destroy) (scope notified): 
+ * @destroy:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 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;
@@ -342,16 +359,25 @@ hb_ft_face_create (FT_Face           ft_
 }
 
 static void
 hb_ft_face_finalize (FT_Face ft_face)
 {
   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 }
 
+/**
+ * hb_ft_face_create_cached:
+ * @ft_face: 
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 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);
 
@@ -363,16 +389,26 @@ hb_ft_face_create_cached (FT_Face ft_fac
 }
 
 static void
 _do_nothing (void)
 {
 }
 
 
+/**
+ * hb_ft_font_create:
+ * @ft_face: (destroy destroy) (scope notified): 
+ * @destroy:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy)
 {
   hb_font_t *font;
   hb_face_t *face;
 
   face = hb_ft_face_create (ft_face, destroy);
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -72,17 +72,17 @@ glib_script_to_script[] =
   HB_SCRIPT_RUNIC,
   HB_SCRIPT_SINHALA,
   HB_SCRIPT_SYRIAC,
   HB_SCRIPT_TAMIL,
   HB_SCRIPT_TELUGU,
   HB_SCRIPT_THAANA,
   HB_SCRIPT_THAI,
   HB_SCRIPT_TIBETAN,
-  HB_SCRIPT_CANADIAN_ABORIGINAL,
+  HB_SCRIPT_CANADIAN_SYLLABICS,
   HB_SCRIPT_YI,
   HB_SCRIPT_TAGALOG,
   HB_SCRIPT_HANUNOO,
   HB_SCRIPT_BUHID,
   HB_SCRIPT_TAGBANWA,
 
   /* Unicode-4.0 additions */
   HB_SCRIPT_BRAILLE,
--- a/gfx/harfbuzz/src/hb-gobject-enums.cc.tmpl
+++ b/gfx/harfbuzz/src/hb-gobject-enums.cc.tmpl
@@ -40,35 +40,34 @@
 
 /*** END file-header ***/
 
 /*** BEGIN file-production ***/
 /* enumerations from "@filename@" */
 /*** END file-production ***/
 
 /*** BEGIN value-header ***/
-inline static /* TODO(behdad) disable these for now until we fix them... */
 GType
 @enum_name@_get_type (void)
 {
-  static volatile gsize g_define_type_id__volatile = 0;
+  static gsize type_id = 0;
 
-  if (g_once_init_enter (&g_define_type_id__volatile))
+  if (g_once_init_enter (&type_id))
     {
       static const G@Type@Value values[] = {
 /*** END value-header ***/
 
 /*** BEGIN value-production ***/
         { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
 /*** END value-production ***/
 
 /*** BEGIN value-tail ***/
         { 0, NULL, NULL }
       };
-      GType g_define_type_id =
+      GType id =
         g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+      g_once_init_leave (&type_id, id);
     }
 
-  return g_define_type_id__volatile;
+  return type_id;
 }
 
 /*** END value-tail ***/
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
@@ -0,0 +1,55 @@
+/*** BEGIN file-header ***/
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * 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_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
+
+#ifndef HB_GOBJECT_ENUMS_H
+#define HB_GOBJECT_ENUMS_H
+
+#include "hb.h"
+
+#include <glib-object.h>
+
+HB_BEGIN_DECLS
+
+
+/*** END file-header ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_ENUMS_H */
+/*** END file-tail ***/
--- a/gfx/harfbuzz/src/hb-gobject-structs.cc
+++ b/gfx/harfbuzz/src/hb-gobject-structs.cc
@@ -32,32 +32,89 @@
 #undef __GNUC__
 #undef __GNUC_MINOR__
 #define __GNUC__ 2
 #define __GNUC_MINOR__ 6
 #endif
 
 #include "hb-gobject.h"
 
-#define _HB_DEFINE_BOXED_TYPE(Name,underscore_name,copy_func,free_func) \
+#define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \
 GType \
-underscore_name##_get_type (void) \
+hb_gobject_##name##_get_type (void) \
 { \
-   static volatile gsize type = 0; \
-   if (g_once_init_enter (&type)) { \
-      GType t = g_boxed_type_register_static (g_intern_static_string (#Name), \
-					      (GBoxedCopyFunc) copy_func, \
-					      (GBoxedFreeFunc) free_func); \
-      g_once_init_leave (&type, t); \
+   static gsize type_id = 0; \
+   if (g_once_init_enter (&type_id)) { \
+      GType id = g_boxed_type_register_static (g_intern_static_string ("hb_" #name "_t"), \
+					       (GBoxedCopyFunc) copy_func, \
+					       (GBoxedFreeFunc) free_func); \
+      g_once_init_leave (&type_id, id); \
    } \
-   return type; \
+   return type_id; \
 }
 
-#define HB_DEFINE_BOXED_TYPE(name) \
-	_HB_DEFINE_BOXED_TYPE (hb_##name, hb_gobject_##name, hb_##name##_reference, hb_##name##_destroy);
+#define HB_DEFINE_OBJECT_TYPE(name) \
+	HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
+
+HB_DEFINE_OBJECT_TYPE (buffer)
+HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (face)
+HB_DEFINE_OBJECT_TYPE (font)
+HB_DEFINE_OBJECT_TYPE (font_funcs)
+HB_DEFINE_OBJECT_TYPE (set)
+HB_DEFINE_OBJECT_TYPE (shape_plan)
+HB_DEFINE_OBJECT_TYPE (unicode_funcs)
+
+
+static hb_feature_t *feature_reference (hb_feature_t *g)
+{
+  hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void feature_destroy (hb_feature_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy)
+
+static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g)
+{
+  hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy)
 
-HB_DEFINE_BOXED_TYPE (buffer)
-HB_DEFINE_BOXED_TYPE (blob)
-HB_DEFINE_BOXED_TYPE (face)
-HB_DEFINE_BOXED_TYPE (font)
-HB_DEFINE_BOXED_TYPE (font_funcs)
-HB_DEFINE_BOXED_TYPE (unicode_funcs)
+static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g)
+{
+  hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy)
 
+static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g)
+{
+  hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy)
+
+static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; }
+static void user_data_key_destroy (hb_user_data_key_t l) { }
+HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy)
+
+
+static hb_language_t *language_reference (hb_language_t *l)
+{
+  hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t));
+  if (unlikely (!c)) return NULL;
+  *c = *l;
+  return c;
+}
+static void language_destroy (hb_language_t *l) { free (l); }
+HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy)
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject-structs.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2011  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_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
+
+#ifndef HB_GOBJECT_STRUCTS_H
+#define HB_GOBJECT_STRUCTS_H
+
+#include "hb.h"
+
+#include <glib-object.h>
+
+HB_BEGIN_DECLS
+
+
+/* Object types */
+
+GType hb_gobject_blob_get_type (void);
+#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
+
+GType hb_gobject_buffer_get_type (void);
+#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
+
+GType hb_gobject_face_get_type (void);
+#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
+
+GType hb_gobject_font_get_type (void);
+#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
+
+GType hb_gobject_font_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
+
+GType hb_gobject_set_get_type (void);
+#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
+
+GType hb_gobject_shape_plan_get_type (void);
+#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
+
+GType hb_gobject_unicode_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
+
+/* Value types */
+
+GType hb_gobject_feature_get_type (void);
+#define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
+
+GType hb_gobject_glyph_info_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
+
+GType hb_gobject_glyph_position_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
+
+GType hb_gobject_segment_properties_get_type (void);
+#define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
+
+GType hb_gobject_user_data_key_get_type (void);
+#define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
+
+/* Currently gobject-introspection doesn't understand that hb_language_t
+ * can be passed by-value.  As such we box it up.  May remove in the
+ * future.
+ *
+ *   https://bugzilla.gnome.org/show_bug.cgi?id=707656
+ */
+GType hb_gobject_language_get_type (void);
+#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ())
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_H */
--- a/gfx/harfbuzz/src/hb-gobject.h
+++ b/gfx/harfbuzz/src/hb-gobject.h
@@ -21,49 +21,20 @@
  * 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_GOBJECT_H
 #define HB_GOBJECT_H
+#define HB_GOBJECT_H_IN
 
 #include "hb.h"
 
-#include <glib-object.h>
+#include "hb-gobject-enums.h"
+#include "hb-gobject-structs.h"
 
 HB_BEGIN_DECLS
-
-
-/* Objects */
-
-#define HB_GOBJECT_TYPE_BLOB hb_gobject_blob_get_type ()
-GType
-hb_gobject_blob_get_type (void);
-
-#define HB_GOBJECT_TYPE_BUFFER hb_gobject_buffer_get_type ()
-GType
-hb_gobject_buffer_get_type (void);
-
-#define HB_GOBJECT_TYPE_FACE hb_gobject_face_get_type ()
-GType
-hb_gobject_face_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT hb_gobject_font_get_type ()
-GType
-hb_gobject_font_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT_FUNCS hb_gobject_font_funcs_get_type ()
-GType
-hb_gobject_font_funcs_get_type (void);
-
-#define HB_GOBJECT_TYPE_UNICODE_FUNCS hb_gobject_unicode_funcs_get_type ()
-GType
-hb_gobject_unicode_funcs_get_type (void);
-
-
-/* Enums */
-
-
 HB_END_DECLS
 
+#undef HB_GOBJECT_H_IN
 #endif /* HB_GOBJECT_H */
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -25,21 +25,20 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #define HB_SHAPER graphite2
 #define hb_graphite2_shaper_font_data_t gr_font
 #include "hb-shaper-impl-private.hh"
 
-#include <graphite2/Font.h>
+#include "hb-graphite2.h"
+
 #include <graphite2/Segment.h>
 
-#include "hb-graphite2.h"
-
 #include "hb-ot-tag.h"
 
 
 HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
 HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
 
 
 /*
--- a/gfx/harfbuzz/src/hb-graphite2.h
+++ b/gfx/harfbuzz/src/hb-graphite2.h
@@ -23,16 +23,18 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
 #ifndef HB_GRAPHITE2_H
 #define HB_GRAPHITE2_H
 
 #include "hb.h"
 
+#include <graphite2/Font.h>
+
 HB_BEGIN_DECLS
 
 
 #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
 
 
 gr_face *
 hb_graphite2_face_get_gr_face (hb_face_t *face);
--- a/gfx/harfbuzz/src/hb-open-type-private.hh
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -637,25 +637,31 @@ struct LongOffset : ULONG
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 /* CheckSum */
 struct CheckSum : ULONG
 {
-  static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
+  /* This is reference implementation from the spec. */
+  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
-    ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
 
     while (Table < EndPtr)
       Sum += *Table++;
     return Sum;
   }
+
+  /* Note: data should be 4byte aligned and have 4byte padding at the end. */
+  inline void set_for_data (const void *data, unsigned int length)
+  { set (CalcTableChecksum ((const ULONG *) data, length)); }
+
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 
 /*
  * Version Numbers
  */
--- a/gfx/harfbuzz/src/hb-ot-head-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
@@ -38,17 +38,17 @@ namespace OT {
 /*
  * head -- Font Header
  */
 
 #define HB_OT_TAG_head HB_TAG('h','e','a','d')
 
 struct head
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_head;
+  static const hb_tag_t tableTag	= 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 typical Type1 usage. */
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
--- a/gfx/harfbuzz/src/hb-ot-hhea-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hhea-table.hh
@@ -37,17 +37,17 @@ namespace OT {
  * hhea -- The Horizontal Header Table
  */
 
 #define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
 
 
 struct hhea
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_hhea;
+  static const hb_tag_t tableTag	= HB_OT_TAG_hhea;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
   protected:
   FixedVersion	version;		/* 0x00010000 for version 1.0. */
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh
@@ -45,17 +45,17 @@ struct LongHorMetric
   USHORT	advanceWidth;
   SHORT		lsb;
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
 struct hmtx
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_hmtx;
+  static const hb_tag_t tableTag	= HB_OT_TAG_hmtx;
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return TRACE_RETURN (true);
   }
 
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -866,19 +866,19 @@ struct Coverage
     }
   }
 
   struct Iter {
     Iter (void) : format (0) {};
     inline void init (const Coverage &c_) {
       format = c_.u.format;
       switch (format) {
-      case 1: return u.format1.init (c_.u.format1);
-      case 2: return u.format2.init (c_.u.format2);
-      default:return;
+      case 1: u.format1.init (c_.u.format1); return;
+      case 2: u.format2.init (c_.u.format2); return;
+      default:                               return;
       }
     }
     inline bool more (void) {
       switch (format) {
       case 1: return u.format1.more ();
       case 2: return u.format2.more ();
       default:return false;
       }
@@ -889,24 +889,24 @@ struct Coverage
       case 2: u.format2.next (); break;
       default:                   break;
       }
     }
     inline uint16_t get_glyph (void) {
       switch (format) {
       case 1: return u.format1.get_glyph ();
       case 2: return u.format2.get_glyph ();
-      default:return true;
+      default:return 0;
       }
     }
     inline uint16_t get_coverage (void) {
       switch (format) {
       case 1: return u.format1.get_coverage ();
       case 2: return u.format2.get_coverage ();
-      default:return true;
+      default:return -1;
       }
     }
 
     private:
     unsigned int format;
     union {
     CoverageFormat1::Iter	format1;
     CoverageFormat2::Iter	format2;
@@ -950,16 +950,29 @@ struct ClassDefFormat1
     unsigned int count = classValue.len;
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass)
         glyphs->add (startGlyph + i);
   }
 
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = classValue.len;
+    if (klass == 0)
+    {
+      /* Match if there's any glyph that is not listed! */
+      hb_codepoint_t g = -1;
+      if (!hb_set_next (glyphs, &g))
+        return false;
+      if (g < startGlyph)
+        return true;
+      g = startGlyph + count - 1;
+      if (hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
         return true;
     return false;
   }
 
   protected:
   USHORT	classFormat;		/* Format identifier--format = 1 */
@@ -993,16 +1006,32 @@ struct ClassDefFormat2
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass)
         rangeRecord[i].add_coverage (glyphs);
   }
 
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = rangeRecord.len;
+    if (klass == 0)
+    {
+      /* Match if there's any glyph that is not listed! */
+      hb_codepoint_t g = (hb_codepoint_t) -1;
+      for (unsigned int i = 0; i < count; i++)
+      {
+	if (!hb_set_next (glyphs, &g))
+	  break;
+	if (g < rangeRecord[i].start)
+	  return true;
+	g = rangeRecord[i].end;
+      }
+      if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
         return true;
     return false;
   }
 
   protected:
   USHORT	classFormat;	/* Format identifier--format = 2 */
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -319,17 +319,17 @@ struct MarkGlyphSets
 
 
 /*
  * GDEF -- The Glyph Definition Table
  */
 
 struct GDEF
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_GDEF;
+  static const hb_tag_t tableTag	= HB_OT_TAG_GDEF;
 
   enum GlyphClasses {
     UnclassifiedGlyph	= 0,
     BaseGlyph		= 1,
     LigatureGlyph	= 2,
     MarkGlyph		= 3,
     ComponentGlyph	= 4
   };
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -705,18 +705,16 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     /* (this+coverage).add_coverage (c->input); // Don't need this. */
 
-    /* TODO only add values for pairs that have nonzero adjustments. */
-
     unsigned int count1 = class1Count;
     const ClassDef &klass1 = this+classDef1;
     for (unsigned int i = 0; i < count1; i++)
       klass1.add_class (c->input, i);
 
     unsigned int count2 = class2Count;
     const ClassDef &klass2 = this+classDef2;
     for (unsigned int i = 0; i < count2; i++)
@@ -1009,17 +1007,16 @@ typedef AnchorMatrix BaseArray;		/* base
 
 struct MarkBasePosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+markCoverage).add_coverage (c->input);
     (this+baseCoverage).add_coverage (c->input);
-    /* TODO only add combinations that have nonzero adjustment. */
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1113,17 +1110,16 @@ typedef OffsetListOf<LigatureAttach> Lig
 
 struct MarkLigPosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+markCoverage).add_coverage (c->input);
     (this+ligatureCoverage).add_coverage (c->input);
-    /* TODO only add combinations that have nonzero adjustment. */
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+markCoverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1229,17 +1225,16 @@ typedef AnchorMatrix Mark2Array;	/* mark
 
 struct MarkMarkPosFormat1
 {
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     (this+mark1Coverage).add_coverage (c->input);
     (this+mark2Coverage).add_coverage (c->input);
-    /* TODO only add combinations that have nonzero adjustment. */
   }
 
   inline const Coverage &get_coverage (void) const
   {
     return this+mark1Coverage;
   }
 
   inline bool apply (hb_apply_context_t *c) const
@@ -1429,17 +1424,28 @@ struct PosLookupSubTable
 };
 
 
 struct PosLookup : Lookup
 {
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
-  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  inline bool is_reverse (void) const
+  {
+    return false;
+  }
+
+  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     c->set_recurse_func (NULL);
     return TRACE_RETURN (dispatch (c));
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
@@ -1461,41 +1467,16 @@ struct PosLookup : Lookup
     TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
       return TRACE_RETURN (false);
     return TRACE_RETURN (dispatch (c));
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
 
-  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
-  {
-    bool ret = false;
-
-    if (unlikely (!c->buffer->len || !c->lookup_mask))
-      return false;
-
-    c->set_recurse_func (apply_recurse_func);
-    c->set_lookup (*this);
-
-    c->buffer->idx = 0;
-
-    while (c->buffer->idx < c->buffer->len)
-    {
-      if (digest->may_have (c->buffer->cur().codepoint) &&
-	  (c->buffer->cur().mask & c->lookup_mask) &&
-	  apply_once (c))
-	ret = true;
-      else
-	c->buffer->idx++;
-    }
-
-    return ret;
-  }
-
   template <typename context_t>
   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
   template <typename context_t>
   inline typename context_t::return_t dispatch (context_t *c) const
   {
     TRACE_DISPATCH (this);
     unsigned int lookup_type = get_type ();
@@ -1519,17 +1500,17 @@ struct PosLookup : Lookup
 typedef OffsetListOf<PosLookup> PosLookupList;
 
 /*
  * GPOS -- The Glyph Positioning Table
  */
 
 struct GPOS : GSUBGPOS
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
+  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
 
   inline const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
 
   inline bool sanitize (hb_sanitize_context_t *c) {
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -32,16 +32,22 @@
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 
 namespace OT {
 
 
 struct SingleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
 	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
@@ -110,16 +116,22 @@ struct SingleSubstFormat1
   SHORT		deltaGlyphID;		/* Add to original GlyphID to get
 					 * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 struct SingleSubstFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -246,16 +258,23 @@ struct SingleSubst
   SingleSubstFormat1	format1;
   SingleSubstFormat2	format2;
   } u;
 };
 
 
 struct Sequence
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    /* For len==0 we don't do anything, so it's harmless. */
+    return TRACE_RETURN (substitute.len <= 1);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->glyphs->add (substitute[i]);
   }
 
@@ -270,21 +289,28 @@ struct Sequence
   inline bool apply (hb_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     if (unlikely (!substitute.len)) return TRACE_RETURN (false);
 
     unsigned int klass = c->buffer->cur().glyph_props() &
 			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
     unsigned int count = substitute.len;
-    for (unsigned int i = 0; i < count; i++) {
-      set_lig_props_for_component (c->buffer->cur(), i);
-      c->output_glyph (substitute.array[i], klass);
+    if (count == 1) /* Special-case to make it in-place. */
+    {
+      c->replace_glyph (substitute.array[0]);
     }
-    c->buffer->skip_glyph ();
+    else
+    {
+      for (unsigned int i = 0; i < count; i++) {
+	set_lig_props_for_component (c->buffer->cur(), i);
+	c->output_glyph (substitute.array[i], klass);
+      }
+      c->buffer->skip_glyph ();
+    }
 
     return TRACE_RETURN (true);
   }
 
   inline bool serialize (hb_serialize_context_t *c,
 			 Supplier<GlyphID> &glyphs,
 			 unsigned int num_glyphs)
   {
@@ -303,16 +329,28 @@ struct Sequence
   ArrayOf<GlyphID>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
 };
 
 struct MultipleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    /* Some tools generate MultipleSubst with each substitute having length 1!
+     * So, check them. */
+    unsigned int count = sequence.len;
+    for (unsigned int i = 0; i < count; i++)
+	if (!(this+sequence[i]).is_inplace (c))
+	  return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+sequence[iter.get_coverage ()]).closure (c);
     }
@@ -428,16 +466,22 @@ struct MultipleSubst
 };
 
 
 typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
 
 struct AlternateSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ())) {
 	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
 	unsigned int count = alt_set.len;
@@ -748,16 +792,22 @@ struct LigatureSet
 		ligature;		/* Array LigatureSet tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, ligature);
 };
 
 struct LigatureSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (false);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
 	(this+ligatureSet[iter.get_coverage ()]).closure (c);
     }
@@ -896,16 +946,22 @@ struct ExtensionSubst : Extension<Extens
   typedef struct SubstLookupSubTable LookupSubTable;
 
   inline bool is_reverse (void) const;
 };
 
 
 struct ReverseChainSingleSubstFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
 
     count = backtrack.len;
@@ -1133,24 +1189,31 @@ struct SubstLookup : Lookup
   inline bool is_reverse (void) const
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubstLookupSubTable::Extension))
       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
+  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_is_inplace_context_t>);
+    return TRACE_RETURN (dispatch (c));
+  }
+
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
     return TRACE_RETURN (dispatch (c));
   }
 
-  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
     c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
     return TRACE_RETURN (dispatch (c));
   }
 
   template <typename set_t>
   inline void add_coverage (set_t *glyphs) const
@@ -1179,64 +1242,16 @@ struct SubstLookup : Lookup
   {
     TRACE_APPLY (this);
     if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
       return TRACE_RETURN (false);
     return TRACE_RETURN (dispatch (c));
   }
 
   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
-  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
-  {
-    bool ret = false;
-
-    if (unlikely (!c->buffer->len || !c->lookup_mask))
-      return false;
-
-    c->set_recurse_func (apply_recurse_func);
-    c->set_lookup (*this);
-
-    if (likely (!is_reverse ()))
-    {
-	/* in/out forward substitution */
-	c->buffer->clear_output ();
-	c->buffer->idx = 0;
-
-	while (c->buffer->idx < c->buffer->len)
-	{
-	  if (digest->may_have (c->buffer->cur().codepoint) &&
-	      (c->buffer->cur().mask & c->lookup_mask) &&
-	      apply_once (c))
-	    ret = true;
-	  else
-	    c->buffer->next_glyph ();
-	}
-	if (ret)
-	  c->buffer->swap_buffers ();
-    }
-    else
-    {
-	/* in-place backward substitution */
-	c->buffer->remove_output ();
-	c->buffer->idx = c->buffer->len - 1;
-	do
-	{
-	  if (digest->may_have (c->buffer->cur().codepoint) &&
-	      (c->buffer->cur().mask & c->lookup_mask) &&
-	      apply_once (c))
-	    ret = true;
-	  else
-	    c->buffer->idx--;
-
-	}
-	while ((int) c->buffer->idx >= 0);
-    }
-
-    return ret;
-  }
 
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
 						  unsigned int i)
   { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
 
   inline bool serialize_single (hb_serialize_context_t *c,
 				uint32_t lookup_props,
 			        Supplier<GlyphID> &glyphs,
@@ -1331,17 +1346,17 @@ struct SubstLookup : Lookup
 typedef OffsetListOf<SubstLookup> SubstLookupList;
 
 /*
  * GSUB -- The Glyph Substitution Table
  */
 
 struct GSUB : GSUBGPOS
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
+  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
 
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
   static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
   inline bool sanitize (hb_sanitize_context_t *c) {
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -39,16 +39,65 @@ namespace OT {
 
 
 #define TRACE_DISPATCH(this) \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
 
 
+
+#ifndef HB_DEBUG_IS_INPLACE
+#define HB_DEBUG_IS_INPLACE (HB_DEBUG+0)
+#endif
+
+#define TRACE_IS_INPLACE(this) \
+	hb_auto_trace_t<HB_DEBUG_IS_INPLACE, bool> trace \
+	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
+	 "");
+
+struct hb_is_inplace_context_t
+{
+  inline const char *get_name (void) { return "IS_INPLACE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_IS_INPLACE;
+  typedef bool return_t;
+  typedef return_t (*recurse_func_t) (hb_is_inplace_context_t *c, unsigned int lookup_index);
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.is_inplace (this); }
+  static return_t default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (return_t r) const { return !r; }
+
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    bool ret = recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return ret;
+  }
+
+  hb_face_t *face;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int debug_depth;
+
+  hb_is_inplace_context_t (hb_face_t *face_,
+			   unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+			   face (face_),
+			   recurse_func (NULL),
+			   nesting_level_left (nesting_level_left_),
+			   debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
 #define TRACE_CLOSURE(this) \
 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	 "");
@@ -153,17 +202,23 @@ struct hb_collect_glyphs_context_t
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
   return_t recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
       return default_return_value ();
 
     /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
-     * glyphs in the recursion.  If output is not requested, we can go home now. */
+     * glyphs in the recursion.  If output is not requested, we can go home now.
+     *
+     * Note further, that the above is not exactly correct.  A recursed lookup
+     * is allowed to match input that is not matched in the context, but that's
+     * not how most fonts are built.  It's possible to relax that and recurse
+     * with all sets here if it proves to be an issue.
+     */
 
     if (output == hb_set_get_empty ())
       return HB_VOID;
 
     hb_set_t *old_before = before;
     hb_set_t *old_input  = input;
     hb_set_t *old_after  = after;
     before = input = after = hb_set_get_empty ();
@@ -267,31 +322,31 @@ struct hb_apply_context_t
   unsigned int lookup_props;
   const GDEF &gdef;
   bool has_glyph_classes;
   unsigned int debug_depth;
 
 
   hb_apply_context_t (unsigned int table_index_,
 		      hb_font_t *font_,
-		      hb_buffer_t *buffer_,
-		      hb_mask_t lookup_mask_,
-		      bool auto_zwj_) :
+		      hb_buffer_t *buffer_) :
 			table_index (table_index_),
 			font (font_), face (font->face), buffer (buffer_),
 			direction (buffer_->props.direction),
-			lookup_mask (lookup_mask_),
-			auto_zwj (auto_zwj_),
+			lookup_mask (1),
+			auto_zwj (true),
 			recurse_func (NULL),
 			nesting_level_left (MAX_NESTING_LEVEL),
 			lookup_props (0),
 			gdef (*hb_ot_layout_from_face (face)->gdef),
 			has_glyph_classes (gdef.has_glyph_classes ()),
 			debug_depth (0) {}
 
+  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
   inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
 
   struct matcher_t
   {
     inline matcher_t (void) :
 	     lookup_props (0),
@@ -812,17 +867,21 @@ static inline void ligate_input (hb_appl
 
   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
   unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
   unsigned int last_lig_id = get_lig_id (c->buffer->cur());
   unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
   unsigned int components_so_far = last_num_components;
 
   if (!is_mark_ligature)
+  {
     set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
+    if (_hb_glyph_info_get_general_category (&c->buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+      _hb_glyph_info_set_general_category (&c->buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+  }
   c->replace_glyph (lig_glyph, klass);
 
   for (unsigned int i = 1; i < count; i++)
   {
     if (!skippy_iter.next ()) return;
 
     while (c->buffer->idx < skippy_iter.idx)
     {
@@ -913,17 +972,17 @@ struct LookupRecord
 
 
 template <typename context_t>
 static inline void recurse_lookups (context_t *c,
 				    unsigned int lookupCount,
 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
-    c->recurse (lookupRecord->lookupListIndex);
+    c->recurse (lookupRecord[i].lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
 				 unsigned int count, /* Including the first glyph */
 				 const USHORT input[], /* Array of input values--start with second glyph */
 				 match_func_t match_func,
 				 const void *match_data,
 				 unsigned int lookupCount,
@@ -952,23 +1011,24 @@ static inline bool apply_lookup (hb_appl
   {
     unsigned int old_pos = c->buffer->idx;
 
     /* Apply a lookup */
     bool done = c->recurse (lookupRecord->lookupListIndex);
 
     lookupRecord++;
     lookupCount--;
-    /* Err, this is wrong if the lookup jumped over some glyphs */
-    i += c->buffer->idx - old_pos;
+    i++;
 
     if (!done)
       goto not_applied;
     else
     {
+      if (c->table_index == 1)
+        c->buffer->idx = old_pos + 1;
       /* Reinitialize iterator. */
       hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
       tmp.set_syllable (syllable);
       skippy_iter = tmp;
     }
   }
   else
   {
@@ -987,23 +1047,24 @@ static inline bool apply_lookup (hb_appl
     {
       unsigned int old_pos = c->buffer->idx;
 
       /* Apply a lookup */
       bool done = c->recurse (lookupRecord->lookupListIndex);
 
       lookupRecord++;
       lookupCount--;
-      /* Err, this is wrong if the lookup jumped over some glyphs */
-      i += c->buffer->idx - old_pos;
+      i++;
 
       if (!done)
 	goto not_applied2;
       else
       {
+	if (c->table_index == 1)
+	  c->buffer->idx = old_pos + 1;
         /* Reinitialize iterator. */
 	hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
 	tmp.set_syllable (syllable);
 	skippy_iter = tmp;
       }
     }
     else
     {
@@ -1091,16 +1152,27 @@ static inline bool context_apply_lookup 
       && apply_lookup (c,
 		       inputCount, input,
 		       lookup_context.funcs.match, lookup_context.match_data,
 		       lookupCount, lookupRecord);
 }
 
 struct Rule
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+    unsigned int count = lookupCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookupRecord[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
     context_closure_lookup (c,
 			    inputCount, input,
 			    lookupCount, lookupRecord,
 			    lookup_context);
@@ -1150,16 +1222,26 @@ struct Rule
   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
 					 * design order */
   public:
   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
 };
 
 struct RuleSet
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if (!(this+rule[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
@@ -1206,16 +1288,26 @@ struct RuleSet
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 
 struct ContextFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
@@ -1292,16 +1384,26 @@ struct ContextFormat1
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 
 struct ContextFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &class_def = this+classDef;
 
@@ -1387,16 +1489,27 @@ struct ContextFormat2
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (8, ruleSet);
 };
 
 
 struct ContextFormat3
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    unsigned int count = lookupCount;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookupRecord[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage[0]).intersects (c->glyphs))
       return;
 
     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
@@ -1549,17 +1662,17 @@ static inline void chain_context_closure
 						 ChainContextClosureLookupContext &lookup_context)
 {
   if (intersects_array (c,
 			backtrackCount, backtrack,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
    && intersects_array (c,
 			inputCount ? inputCount - 1 : 0, input,
 			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-  && intersects_array (c,
+   && intersects_array (c,
 		       lookaheadCount, lookahead,
 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
     recurse_lookups (c,
 		     lookupCount, lookupRecord);
 }
 
 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
 						        unsigned int backtrackCount,
@@ -1628,16 +1741,29 @@ static inline bool chain_context_apply_l
       && apply_lookup (c,
 		       inputCount, input,
 		       lookup_context.funcs.match, lookup_context.match_data[1],
 		       lookupCount, lookupRecord);
 }
 
 struct ChainRule
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    unsigned int count = lookup.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookup.array[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     chain_context_closure_lookup (c,
 				  backtrack.len, backtrack.array,
@@ -1713,16 +1839,26 @@ struct ChainRule
 		lookupX;		/* Array of LookupRecords--in
 					 * design order) */
   public:
   DEFINE_SIZE_MIN (8);
 };
 
 struct ChainRuleSet
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if (!(this+rule[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
@@ -1766,16 +1902,26 @@ struct ChainRuleSet
 		rule;			/* Array of ChainRule tables
 					 * ordered by preference */
   public:
   DEFINE_SIZE_ARRAY (2, rule);
 };
 
 struct ChainContextFormat1
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       {NULL, NULL, NULL}
@@ -1849,16 +1995,26 @@ struct ChainContextFormat1
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by Coverage Index */
   public:
   DEFINE_SIZE_ARRAY (6, ruleSet);
 };
 
 struct ChainContextFormat2
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+ruleSet[i]).is_inplace (c))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
@@ -1973,16 +2129,30 @@ struct ChainContextFormat2
 		ruleSet;		/* Array of ChainRuleSet tables
 					 * ordered by class */
   public:
   DEFINE_SIZE_ARRAY (12, ruleSet);
 };
 
 struct ChainContextFormat3
 {
+  inline bool is_inplace (hb_is_inplace_context_t *c) const
+  {
+    TRACE_IS_INPLACE (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+
+    unsigned int count = lookup.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!c->recurse (lookup.array[i].lookupListIndex))
+        return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
       return;
 
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh
@@ -0,0 +1,229 @@
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * 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_LAYOUT_JSTF_TABLE_HH
+#define HB_OT_LAYOUT_JSTF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-gpos-table.hh"
+
+
+namespace OT {
+
+
+/*
+ * JstfModList -- Justification Modification List Tables
+ */
+
+typedef IndexArray JstfModList;
+
+
+/*
+ * JstfMax -- Justification Maximum Table
+ */
+
+typedef OffsetListOf<PosLookup> JstfMax;
+
+
+/*
+ * JstfPriority -- Justification Priority Table
+ */
+
+struct JstfPriority
+{
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+			 shrinkageEnableGSUB.sanitize (c, this) &&
+			 shrinkageDisableGSUB.sanitize (c, this) &&
+			 shrinkageEnableGPOS.sanitize (c, this) &&
+			 shrinkageDisableGPOS.sanitize (c, this) &&
+			 shrinkageJstfMax.sanitize (c, this) &&
+			 extensionEnableGSUB.sanitize (c, this) &&
+			 extensionDisableGSUB.sanitize (c, this) &&
+			 extensionEnableGPOS.sanitize (c, this) &&
+			 extensionDisableGPOS.sanitize (c, this) &&
+			 extensionJstfMax.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<JstfModList>
+		shrinkageEnableGSUB;	/* Offset to Shrinkage Enable GSUB
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		shrinkageDisableGSUB;	/* Offset to Shrinkage Disable GSUB
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		shrinkageEnableGPOS;	/* Offset to Shrinkage Enable GPOS
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		shrinkageDisableGPOS;	/* Offset to Shrinkage Disable GPOS
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+		shrinkageJstfMax;	/* Offset to Shrinkage JstfMax table--
+					 * from beginning of JstfPriority table
+					 * --may be NULL */
+  OffsetTo<JstfModList>
+		extensionEnableGSUB;	/* Offset to Extension Enable GSUB
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		extensionDisableGSUB;	/* Offset to Extension Disable GSUB
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		extensionEnableGPOS;	/* Offset to Extension Enable GPOS
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+		extensionDisableGPOS;	/* Offset to Extension Disable GPOS
+					 * JstfModList table--from beginning of
+					 * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+		extensionJstfMax;	/* Offset to Extension JstfMax table--
+					 * from beginning of JstfPriority table
+					 * --may be NULL */
+
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+
+/*
+ * JstfLangSys -- Justification Language System Table
+ */
+
+struct JstfLangSys : OffsetListOf<JstfPriority>
+{
+  inline bool sanitize (hb_sanitize_context_t *c,
+			const Record<JstfLangSys>::sanitize_closure_t * = NULL) {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
+  }
+};
+
+
+/*
+ * ExtenderGlyphs -- Extender Glyph Table
+ */
+
+typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+
+
+/*
+ * JstfScript -- The Justification Table
+ */
+
+struct JstfScript
+{
+  inline unsigned int get_lang_sys_count (void) const
+  { return langSys.len; }
+  inline const Tag& get_lang_sys_tag (unsigned int i) const
+  { return langSys.get_tag (i); }
+  inline unsigned int get_lang_sys_tags (unsigned int start_offset,
+					 unsigned int *lang_sys_count /* IN/OUT */,
+					 hb_tag_t     *lang_sys_tags /* OUT */) const
+  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
+  inline const JstfLangSys& get_lang_sys (unsigned int i) const
+  {
+    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+    return this+langSys[i].offset;
+  }
+  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+  { return langSys.find_index (tag, index); }
+
+  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
+  inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+			const Record<JstfScript>::sanitize_closure_t * = NULL) {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
+			 defaultLangSys.sanitize (c, this) &&
+			 langSys.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<ExtenderGlyphs>
+		extenderGlyphs;	/* Offset to ExtenderGlyph table--from beginning
+				 * of JstfScript table-may be NULL */
+  OffsetTo<JstfLangSys>
+		defaultLangSys;	/* Offset to DefaultJstfLangSys table--from
+				 * beginning of JstfScript table--may be Null */
+  RecordArrayOf<JstfLangSys>
+		langSys;	/* Array of JstfLangSysRecords--listed
+				 * alphabetically by LangSysTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, langSys);
+};
+
+
+/*
+ * JSTF -- The Justification Table
+ */
+
+struct JSTF
+{
+  static const hb_tag_t tableTag	= HB_OT_TAG_JSTF;
+
+  inline unsigned int get_script_count (void) const
+  { return scriptList.len; }
+  inline const Tag& get_script_tag (unsigned int i) const
+  { return scriptList.get_tag (i); }
+  inline unsigned int get_script_tags (unsigned int start_offset,
+				       unsigned int *script_count /* IN/OUT */,
+				       hb_tag_t     *script_tags /* OUT */) const
+  { return scriptList.get_tags (start_offset, script_count, script_tags); }
+  inline const JstfScript& get_script (unsigned int i) const
+  { return this+scriptList[i].offset; }
+  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+  { return scriptList.find_index (tag, index); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
+			 scriptList.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion	version;	/* Version of the JSTF table--initially set
+				 * to 0x00010000 */
+  RecordArrayOf<JstfScript>
+		scriptList;  	/* Array of JstfScripts--listed
+				 * alphabetically by ScriptTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, scriptList);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_JSTF_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -53,16 +53,22 @@ inline void
 {
   info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
 			   (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) |
 			   (info->codepoint == 0x200C ? 0x40 : 0) |
 			   (info->codepoint == 0x200D ? 0x20 : 0);
   info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
 }
 
+inline void
+_hb_glyph_info_set_general_category (hb_glyph_info_t *info, hb_unicode_general_category_t gen_cat)
+{
+  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~0x1F);
+}
+
 inline hb_unicode_general_category_t
 _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
 {
   return (hb_unicode_general_category_t) (info->unicode_props0() & 0x1F);
 }
 
 inline void
 _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class)
@@ -197,41 +203,41 @@ hb_ot_layout_lookup_would_substitute_fas
 					   hb_bool_t             zero_context);
 
 
 /* Should be called before all the substitute_lookup's are done. */
 HB_INTERNAL void
 hb_ot_layout_substitute_start (hb_font_t    *font,
 			       hb_buffer_t  *buffer);
 
-HB_INTERNAL hb_bool_t
-hb_ot_layout_substitute_lookup (hb_font_t    *font,
-				hb_buffer_t  *buffer,
-				unsigned int  lookup_index,
-				hb_mask_t     mask,
-				hb_bool_t     auto_zwj);
+
+struct hb_ot_layout_lookup_accelerator_t;
+
+namespace OT {
+  struct hb_apply_context_t;
+  struct SubstLookup;
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+				const OT::SubstLookup &lookup,
+				const hb_ot_layout_lookup_accelerator_t &accel);
+
 
 /* Should be called after all the substitute_lookup's are done */
 HB_INTERNAL void
 hb_ot_layout_substitute_finish (hb_font_t    *font,
 				hb_buffer_t  *buffer);
 
 
 /* Should be called before all the position_lookup's are done.  Resets positions to zero. */
 HB_INTERNAL void
 hb_ot_layout_position_start (hb_font_t    *font,
 			     hb_buffer_t  *buffer);
 
-HB_INTERNAL hb_bool_t
-hb_ot_layout_position_lookup (hb_font_t    *font,
-			      hb_buffer_t  *buffer,
-			      unsigned int  lookup_index,
-			      hb_mask_t     mask,
-			      hb_bool_t     auto_zwj);
-
 /* Should be called after all the position_lookup's are done */
 HB_INTERNAL void
 hb_ot_layout_position_finish (hb_font_t    *font,
 			      hb_buffer_t  *buffer);
 
 
 
 /*
@@ -239,31 +245,48 @@ hb_ot_layout_position_finish (hb_font_t 
  */
 
 namespace OT {
   struct GDEF;
   struct GSUB;
   struct GPOS;
 }
 
+struct hb_ot_layout_lookup_accelerator_t
+{
+  template <typename TLookup>
+  inline void init (const TLookup &lookup)
+  {
+    digest.init ();
+    lookup.add_coverage (&digest);
+  }
+
+  template <typename TLookup>
+  inline void fini (const TLookup &lookup)
+  {
+  }
+
+  hb_set_digest_t digest;
+};
+
 struct hb_ot_layout_t
 {
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
 
   const struct OT::GDEF *gdef;
   const struct OT::GSUB *gsub;
   const struct OT::GPOS *gpos;
 
   unsigned int gsub_lookup_count;
   unsigned int gpos_lookup_count;
 
-  hb_set_digest_t *gsub_digests;
-  hb_set_digest_t *gpos_digests;
+  hb_ot_layout_lookup_accelerator_t *gsub_accels;
+  hb_ot_layout_lookup_accelerator_t *gpos_accels;
 };
 
 
 HB_INTERNAL hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face);
 
 HB_INTERNAL void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -1,13 +1,13 @@
 /*
  * Copyright © 1998-2004  David Turner and Werner Lemberg
  * Copyright © 2006  Behdad Esfahbod
  * Copyright © 2007,2008,2009  Red Hat, Inc.
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -28,16 +28,19 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-layout-private.hh"
 
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-layout-jstf-table.hh"
+
+#include "hb-ot-map-private.hh"
 
 #include <stdlib.h>
 #include <string.h>
 
 
 HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
 
 hb_ot_layout_t *
@@ -54,50 +57,49 @@ hb_ot_layout_t *
   layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
   layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
   layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
 
   layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
   layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
 
-  layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
-  layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
+  layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+  layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
 
-  if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
-		(layout->gpos_lookup_count && !layout->gpos_digests)))
+  if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
+		(layout->gpos_lookup_count && !layout->gpos_accels)))
   {
     _hb_ot_layout_destroy (layout);
     return NULL;
   }
 
   for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
-  {
-    layout->gsub_digests[i].init ();
-    layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]);
-  }
+    layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
   for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
-  {
-    layout->gpos_digests[i].init ();
-    layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]);
-  }
+    layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
 
   return layout;
 }
 
 void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
 {
+  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+    layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
+  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+    layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
+
+  free (layout->gsub_accels);
+  free (layout->gpos_accels);
+
   hb_blob_destroy (layout->gdef_blob);
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
-  free (layout->gsub_digests);
-  free (layout->gpos_digests);
-
   free (layout);
 }
 
 static inline const OT::GDEF&
 _get_gdef (hb_face_t *face)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
   return *hb_ot_layout_from_face (face)->gdef;
@@ -440,29 +442,29 @@ static void
 static void
 _hb_ot_layout_collect_lookups_features (hb_face_t      *face,
 					hb_tag_t        table_tag,
 					unsigned int    script_index,
 					unsigned int    language_index,
 					const hb_tag_t *features,
 					hb_set_t       *lookup_indexes /* OUT */)
 {
-  unsigned int required_feature_index;
-  if (hb_ot_layout_language_get_required_feature_index (face,
-							table_tag,
-							script_index,
-							language_index,
-							&required_feature_index))
-    _hb_ot_layout_collect_lookups_lookups (face,
-					   table_tag,
-					   required_feature_index,
-					   lookup_indexes);
-
   if (!features)
   {
+    unsigned int required_feature_index;
+    if (hb_ot_layout_language_get_required_feature_index (face,
+							  table_tag,
+							  script_index,
+							  language_index,
+							  &required_feature_index))
+      _hb_ot_layout_collect_lookups_lookups (face,
+					     table_tag,
+					     required_feature_index,
+					     lookup_indexes);
+
     /* All features */
     unsigned int feature_indices[32];
     unsigned int offset, len;
 
     offset = 0;
     do {
       len = ARRAY_LENGTH (feature_indices);
       hb_ot_layout_language_get_feature_indexes (face,
@@ -608,23 +610,23 @@ hb_ot_layout_lookup_collect_glyphs (hb_f
 				     glyphs_after,
 				     glyphs_output);
 
   switch (table_tag)
   {
     case HB_OT_TAG_GSUB:
     {
       const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
-      l.collect_glyphs_lookup (&c);
+      l.collect_glyphs (&c);
       return;
     }
     case HB_OT_TAG_GPOS:
     {
       const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
-      l.collect_glyphs_lookup (&c);
+      l.collect_glyphs (&c);
       return;
     }
   }
 }
 
 
 /*
  * OT::GSUB
@@ -654,41 +656,25 @@ hb_ot_layout_lookup_would_substitute_fas
 					   unsigned int          glyphs_length,
 					   hb_bool_t             zero_context)
 {
   if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
   OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
 
   const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
 
-  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
+  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
 }
 
 void
 hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GSUB::substitute_start (font, buffer);
 }
 
-hb_bool_t
-hb_ot_layout_substitute_lookup (hb_font_t    *font,
-				hb_buffer_t  *buffer,
-				unsigned int  lookup_index,
-				hb_mask_t     mask,
-				hb_bool_t     auto_zwj)
-{
-  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
-
-  OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj);
-
-  const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);
-
-  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
-}
-
 void
 hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GSUB::substitute_finish (font, buffer);
 }
 
 void
 hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
@@ -713,32 +699,16 @@ hb_ot_layout_has_positioning (hb_face_t 
 }
 
 void
 hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_start (font, buffer);
 }
 
-hb_bool_t
-hb_ot_layout_position_lookup (hb_font_t    *font,
-			      hb_buffer_t  *buffer,
-			      unsigned int  lookup_index,
-			      hb_mask_t     mask,
-			      hb_bool_t     auto_zwj)
-{
-  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
-
-  OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj);
-
-  const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);
-
-  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
-}
-
 void
 hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
 {
   OT::GPOS::position_finish (font, buffer);
 }
 
 hb_bool_t
 hb_ot_layout_get_size_params (hb_face_t    *face,
@@ -779,8 +749,163 @@ hb_ot_layout_get_size_params (hb_face_t 
   PARAM (subfamily_id, subfamilyID);
   PARAM (subfamily_name_id, subfamilyNameID);
   PARAM (range_start, rangeStart);
   PARAM (range_end, rangeEnd);
 #undef PARAM
 
   return false;
 }
+
+
+/*
+ * Parts of different types are implemented here such that they have direct
+ * access to GSUB/GPOS lookups.
+ */
+
+
+struct GSUBProxy
+{
+  static const unsigned int table_index = 0;
+  typedef OT::SubstLookup Lookup;
+
+  GSUBProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gsub),
+    accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+
+  const OT::GSUB &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+struct GPOSProxy
+{
+  static const unsigned int table_index = 1;
+  typedef OT::PosLookup Lookup;
+
+  GPOSProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gpos),
+    accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+
+  const OT::GPOS &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+
+template <typename Lookup>
+static inline bool apply_once (OT::hb_apply_context_t *c,
+			       const Lookup &lookup)
+{
+  if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
+    return false;
+  return lookup.dispatch (c);
+}
+
+template <typename Proxy>
+static inline bool
+apply_string (OT::hb_apply_context_t *c,
+	      const typename Proxy::Lookup &lookup,
+	      const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  bool ret = false;
+  OT::hb_is_inplace_context_t inplace_c (c->face);
+  bool inplace = lookup.is_inplace (&inplace_c);
+
+  if (unlikely (!c->buffer->len || !c->lookup_mask))
+    return false;
+
+  c->set_lookup (lookup);
+
+  if (likely (!lookup.is_reverse ()))
+  {
+    /* in/out forward substitution/positioning */
+    if (Proxy::table_index == 0)
+      c->buffer->clear_output ();
+    c->buffer->idx = 0;
+
+    while (c->buffer->idx < c->buffer->len)
+    {
+      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
+	  (c->buffer->cur().mask & c->lookup_mask) &&
+	  apply_once (c, lookup))
+	ret = true;
+      else
+	c->buffer->next_glyph ();
+    }
+    if (ret)
+    {
+      if (!inplace)
+	c->buffer->swap_buffers ();
+      else
+        assert (!c->buffer->has_separate_output ());
+    }
+  }
+  else
+  {
+    /* in-place backward substitution/positioning */
+    if (Proxy::table_index == 0)
+      c->buffer->remove_output ();
+    c->buffer->idx = c->buffer->len - 1;
+    do
+    {
+      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
+	  (c->buffer->cur().mask & c->lookup_mask) &&
+	  apply_once (c, lookup))
+	ret = true;
+      else
+	c->buffer->idx--;
+
+    }
+    while ((int) c->buffer->idx >= 0);
+  }
+
+  return ret;
+}
+
+template <typename Proxy>
+inline void hb_ot_map_t::apply (const Proxy &proxy,
+				const hb_ot_shape_plan_t *plan,
+				hb_font_t *font,
+				hb_buffer_t *buffer) const
+{
+  const unsigned int table_index = proxy.table_index;
+  unsigned int i = 0;
+  OT::hb_apply_context_t c (table_index, font, buffer);
+  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+    const stage_map_t *stage = &stages[table_index][stage_index];
+    for (; i < stage->last_lookup; i++)
+    {
+      unsigned int lookup_index = lookups[table_index][i].index;
+      c.set_lookup_mask (lookups[table_index][i].mask);
+      c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+      apply_string<Proxy> (&c,
+			   proxy.table.get_lookup (lookup_index),
+			   proxy.accels[lookup_index]);
+    }
+
+    if (stage->pause_func)
+    {
+      buffer->clear_output ();
+      stage->pause_func (plan, font, buffer);
+    }
+  }
+}
+
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+  GSUBProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
+}
+
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+  GPOSProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+				const OT::SubstLookup &lookup,
+				const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  apply_string<GSUBProxy> (c, lookup, accel);
+}
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -36,16 +36,17 @@
 #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')
+#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
 
 
 /*
  * GDEF
  */
 
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2010,2011,2012  Google, Inc.
+ * Copyright © 2010,2011,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -26,18 +26,18 @@
  * 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-private.hh"
 
+struct hb_ot_shape_plan_t;
 
 static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
 
 struct hb_ot_map_t
 {
   friend struct hb_ot_map_builder_t;
 
   public:
@@ -62,19 +62,19 @@ struct hb_ot_map_t
     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; }
   };
 
   typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
 
-  struct pause_map_t {
-    unsigned int num_lookups; /* Cumulative */
-    pause_func_t callback;
+  struct stage_map_t {
+    unsigned int last_lookup; /* Cumulative */
+    pause_func_t pause_func;
   };
 
 
   hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
 
   inline hb_mask_t get_global_mask (void) const { return global_mask; }
 
   inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
@@ -105,33 +105,37 @@ struct hb_ot_map_t
 
   inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
 				 const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
     if (unlikely (stage == (unsigned int) -1)) {
       *plookups = NULL;
       *lookup_count = 0;
       return;
     }
-    assert (stage <= pauses[table_index].len);
-    unsigned int start = stage ? pauses[table_index][stage - 1].num_lookups : 0;
-    unsigned int end   = stage < pauses[table_index].len ? pauses[table_index][stage].num_lookups : lookups[table_index].len;
+    assert (stage <= stages[table_index].len);
+    unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
+    unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
     *plookups = &lookups[table_index][start];
     *lookup_count = end - start;
   }
 
   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
+  template <typename Proxy>
+  HB_INTERNAL inline void apply (const Proxy &proxy,
+				 const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
   HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 
   inline void finish (void) {
     features.finish ();
-    lookups[0].finish ();
-    lookups[1].finish ();
-    pauses[0].finish ();
-    pauses[1].finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      lookups[table_index].finish ();
+      stages[table_index].finish ();
+    }
   }
 
   public:
   hb_tag_t chosen_script[2];
   bool found_script[2];
 
   private:
 
@@ -140,17 +144,17 @@ struct hb_ot_map_t
 				unsigned int  feature_index,
 				hb_mask_t     mask,
 				bool          auto_zwj);
 
   hb_mask_t global_mask;
 
   hb_prealloced_array_t<feature_map_t, 8> features;
   hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
-  hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
 };
 
 enum hb_ot_map_feature_flags_t {
   F_NONE		= 0x0000,
   F_GLOBAL		= 0x0001,
   F_HAS_FALLBACK	= 0x0002,
   F_MANUAL_ZWJ		= 0x0004
 };
@@ -190,52 +194,54 @@ struct hb_ot_map_builder_t
   { add_pause (0, pause_func); }
   inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
   { add_pause (1, pause_func); }
 
   HB_INTERNAL void compile (struct hb_ot_map_t &m);
 
   inline void finish (void) {
     feature_infos.finish ();
-    pauses[0].finish ();
-    pauses[1].finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      stages[table_index].finish ();
+    }
   }
 
   private:
 
   struct feature_info_t {
     hb_tag_t tag;
     unsigned int seq; /* sequence#, used for stable sorting only */
     unsigned int max_value;
     hb_ot_map_feature_flags_t flags;
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
     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 pause_info_t {
-    unsigned int stage;
-    hb_ot_map_t::pause_func_t callback;
+  struct stage_info_t {
+    unsigned int index;
+    hb_ot_map_t::pause_func_t pause_func;
   };
 
   HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
 
   public:
 
   hb_face_t *face;
   hb_segment_properties_t props;
 
   hb_tag_t chosen_script[2];
   bool found_script[2];
   unsigned int script_index[2], language_index[2];
 
   private:
 
   unsigned int current_stage[2]; /* GSUB/GPOS */
-  hb_prealloced_array_t<feature_info_t,16> feature_infos;
-  hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<feature_info_t, 32> feature_infos;
+  hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
 };
 
 
 
 #endif /* HB_OT_MAP_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-map.cc
+++ b/gfx/harfbuzz/src/hb-ot-map.cc
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -23,16 +23,18 @@
  * 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-layout-private.hh"
+
 
 void
 hb_ot_map_t::add_lookups (hb_face_t    *face,
 			  unsigned int  table_index,
 			  unsigned int  feature_index,
 			  hb_mask_t     mask,
 			  bool          auto_zwj)
 {
@@ -95,77 +97,29 @@ void hb_ot_map_builder_t::add_feature (h
   info->seq = feature_infos.len;
   info->max_value = value;
   info->flags = flags;
   info->default_value = (flags & F_GLOBAL) ? value : 0;
   info->stage[0] = current_stage[0];
   info->stage[1] = current_stage[1];
 }
 
-/* Keep the next two functions in sync. */
-
-void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
-{
-  const unsigned int table_index = 0;
-  unsigned int i = 0;
-
-  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
-    const pause_map_t *pause = &pauses[table_index][pause_index];
-    for (; i < pause->num_lookups; i++)
-      hb_ot_layout_substitute_lookup (font, buffer,
-				      lookups[table_index][i].index,
-				      lookups[table_index][i].mask,
-				      lookups[table_index][i].auto_zwj);
-
-    buffer->clear_output ();
-
-    if (pause->callback)
-      pause->callback (plan, font, buffer);
-  }
-
-  for (; i < lookups[table_index].len; i++)
-    hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index,
-				    lookups[table_index][i].mask,
-				    lookups[table_index][i].auto_zwj);
-}
-
-void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
-{
-  const unsigned int table_index = 1;
-  unsigned int i = 0;
-
-  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
-    const pause_map_t *pause = &pauses[table_index][pause_index];
-    for (; i < pause->num_lookups; i++)
-      hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index,
-				    lookups[table_index][i].mask,
-				    lookups[table_index][i].auto_zwj);
-
-    if (pause->callback)
-      pause->callback (plan, font, buffer);
-  }
-
-  for (; i < lookups[table_index].len; i++)
-    hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index,
-				  lookups[table_index][i].mask,
-				  lookups[table_index][i].auto_zwj);
-}
 
 void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
   for (unsigned int i = 0; i < lookups[table_index].len; i++)
     hb_set_add (lookups_out, lookups[table_index][i].index);
 }
 
 void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 {
-  pause_info_t *p = pauses[table_index].push ();
-  if (likely (p)) {
-    p->stage = current_stage[table_index];
-    p->callback = pause_func;
+  stage_info_t *s = stages[table_index].push ();
+  if (likely (s)) {
+    s->index = current_stage[table_index];
+    s->pause_func = pause_func;
   }
 
   current_stage[table_index]++;
 }
 
 void
 hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 {
@@ -272,17 +226,17 @@ hb_ot_map_builder_t::compile (hb_ot_map_
     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))
       m.add_lookups (face, table_index, required_feature_index, 1, true);
 
-    unsigned int pause_index = 0;
+    unsigned int stage_index = 0;
     unsigned int last_num_lookups = 0;
     for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
     {
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
 	  m.add_lookups (face, table_index,
 			 m.features[i].index[table_index],
 			 m.features[i].mask,
@@ -302,20 +256,20 @@ hb_ot_map_builder_t::compile (hb_ot_map_
 	    m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
 	    m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
 	  }
 	m.lookups[table_index].shrink (j + 1);
       }
 
       last_num_lookups = m.lookups[table_index].len;
 
-      if (pause_index < pauses[table_index].len && pauses[table_index][pause_index].stage == stage) {
-	hb_ot_map_t::pause_map_t *pause_map = m.pauses[table_index].push ();
-	if (likely (pause_map)) {
-	  pause_map->num_lookups = last_num_lookups;
-	  pause_map->callback = pauses[table_index][pause_index].callback;
+      if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
+	hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
+	if (likely (stage_map)) {
+	  stage_map->last_lookup = last_num_lookups;
+	  stage_map->pause_func = stages[table_index][stage_index].pause_func;
 	}
 
-	pause_index++;
+	stage_index++;
       }
     }
   }
 }
--- a/gfx/harfbuzz/src/hb-ot-maxp-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-maxp-table.hh
@@ -36,17 +36,17 @@ namespace OT {
 /*
  * maxp -- The Maximum Profile Table
  */
 
 #define HB_OT_TAG_maxp HB_TAG('m','a','x','p')
 
 struct maxp
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_maxp;
+  static const hb_tag_t tableTag	= HB_OT_TAG_maxp;
 
   inline unsigned int get_num_glyphs (void) const {
     return numGlyphs;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
--- a/gfx/harfbuzz/src/hb-ot-name-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-name-table.hh
@@ -69,17 +69,17 @@ struct NameRecord
   USHORT	length;		/* String length (in bytes). */
   USHORT	offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct name
 {
-  static const hb_tag_t Tag	= HB_OT_TAG_name;
+  static const hb_tag_t tableTag	= HB_OT_TAG_name;
 
   inline unsigned int get_name (unsigned int platform_id,
 				unsigned int encoding_id,
 				unsigned int language_id,
 				unsigned int name_id,
 				void *buffer,
 				unsigned int buffer_length) const
   {
@@ -93,16 +93,19 @@ struct name
     if (!match)
       return 0;
 
     unsigned int length = MIN (buffer_length, (unsigned int) match->length);
     memcpy (buffer, (char *) this + stringOffset + match->offset, length);
     return length;
   }
 
+  inline unsigned int get_size (void) const
+  { return min_size + count * nameRecord[0].min_size; }
+
   inline bool sanitize_records (hb_sanitize_context_t *c) {
     TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
     for (unsigned int i = 0; i < _count; i++)
       if (!nameRecord[i].sanitize (c, string_pool)) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
@@ -111,17 +114,16 @@ struct name
     TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
 			 likely (format == 0 || format == 1) &&
 			 c->check_array (nameRecord, nameRecord[0].static_size, count) &&
 			 sanitize_records (c));
   }
 
   /* We only implement format 0 for now. */
-  protected:
   USHORT	format;			/* Format selector (=0/1). */
   USHORT	count;			/* Number of name records. */
   Offset	stringOffset;		/* Offset to start of string storage (from start of table). */
   NameRecord	nameRecord[VAR];	/* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
 };
 
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -194,62 +194,67 @@ arabic_fallback_synthesize_lookup (const
 }
 
 struct arabic_fallback_plan_t
 {
   ASSERT_POD ();
 
   hb_mask_t mask_array[ARABIC_NUM_FALLBACK_FEATURES];
   OT::SubstLookup *lookup_array[ARABIC_NUM_FALLBACK_FEATURES];
-  hb_set_digest_t digest_array[ARABIC_NUM_FALLBACK_FEATURES];
+  hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_NUM_FALLBACK_FEATURES];
 };
 
 static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
 
 static arabic_fallback_plan_t *
 arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
 			     hb_font_t *font)
 {
   arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
   if (unlikely (!fallback_plan))
     return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
 
   for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
   {
-    fallback_plan->digest_array[i].init ();
     fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]);
     if (fallback_plan->mask_array[i]) {
       fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i);
       if (fallback_plan->lookup_array[i])
-	fallback_plan->lookup_array[i]->add_coverage (&fallback_plan->digest_array[i]);
+	fallback_plan->accel_array[i].init (*fallback_plan->lookup_array[i]);
     }
   }
 
   return fallback_plan;
 }
 
 static void
 arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
 {
   if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
     return;
 
   for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
     if (fallback_plan->lookup_array[i])
+    {
+      fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]);
       free (fallback_plan->lookup_array[i]);
+    }
 
   free (fallback_plan);
 }
 
 static void
 arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
 			    hb_font_t *font,
 			    hb_buffer_t *buffer)
 {
+  OT::hb_apply_context_t c (0, font, buffer);
   for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++)
     if (fallback_plan->lookup_array[i]) {
-      OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i], true/*auto_zwj*/);
-      fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]);
+      c.set_lookup_mask (fallback_plan->mask_array[i]);
+      hb_ot_layout_substitute_lookup (&c,
+				      *fallback_plan->lookup_array[i],
+				      fallback_plan->accel_array[i]);
     }
 }
 
 
 #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -188,17 +188,16 @@ collect_features_arabic (hb_ot_shape_pla
 
   map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
   map->add_gsub_pause (arabic_fallback_shape);
 
   map->add_global_bool_feature (HB_TAG('c','a','l','t'));
   map->add_gsub_pause (NULL);
 
   map->add_global_bool_feature (HB_TAG('c','s','w','h'));
-  map->add_global_bool_feature (HB_TAG('d','l','i','g'));
   map->add_global_bool_feature (HB_TAG('m','s','e','t'));
 }
 
 #include "hb-ot-shape-complex-arabic-fallback.hh"
 
 struct arabic_shape_plan_t
 {
   ASSERT_POD ();
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -27,17 +27,17 @@
  */
 
 #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
 #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
 
 #include "hb-private.hh"
 
 
-#line 36 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 36 "hb-ot-shape-complex-indic-machine.hh.tmp"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
 	1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 
 	5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 
 	16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 
 	6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 
 	4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 
 	7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 
 	5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 
@@ -1264,48 +1264,48 @@ static const int indic_syllable_machine_
 
 static void
 find_syllables (hb_buffer_t *buffer)
 {
   unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   
-#line 1273 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1273 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	cs = indic_syllable_machine_start;
 	ts = 0;
 	te = 0;
 	act = 0;
 	}
 
 #line 112 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
   pe = eof = buffer->len;
 
   unsigned int last = 0;
   unsigned int syllable_serial = 1;
   
-#line 1290 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1290 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	int _slen;
 	int _trans;
 	const unsigned char *_keys;
 	const short *_inds;
 	if ( p == pe )
 		goto _test_eof;
 _resume:
 	switch ( _indic_syllable_machine_from_state_actions[cs] ) {
 	case 10:
 #line 1 "NONE"
 	{ts = p;}
 	break;
-#line 1304 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1304 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 	_keys = _indic_syllable_machine_trans_keys + (cs<<1);
 	_inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
 
 	_slen = _indic_syllable_machine_key_spans[cs];
 	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
 		( info[p].indic_category()) <= _keys[1] ?
@@ -1406,26 +1406,26 @@ find_syllables (hb_buffer_t *buffer)
 	{act = 4;}
 	break;
 	case 12:
 #line 1 "NONE"
 	{te = p+1;}
 #line 87 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{act = 5;}
 	break;
-#line 1415 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1415 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 _again:
 	switch ( _indic_syllable_machine_to_state_actions[cs] ) {
 	case 9:
 #line 1 "NONE"
 	{ts = 0;}
 	break;
-#line 1424 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
+#line 1424 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 	if ( ++p != pe )
 		goto _resume;
 	_test_eof: {}
 	if ( p == eof )
 	{
 	if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -314,16 +314,17 @@ static const indic_config_t indic_config
   {HB_SCRIPT_GUJARATI,	true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
   {HB_SCRIPT_ORIYA,	true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_TAMIL,	true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_TELUGU,	true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT},
   {HB_SCRIPT_KANNADA,	true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
   {HB_SCRIPT_MALAYALAM,	true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA},
   {HB_SCRIPT_SINHALA,	false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT},
   {HB_SCRIPT_KHMER,	false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA},
+  {HB_SCRIPT_JAVANESE,	false,0xA9C0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT},
 };
 
 
 
 /*
  * Indic shaper.
  */
 
@@ -439,16 +440,20 @@ collect_features_indic (hb_ot_shape_plan
 
 static void
 override_features_indic (hb_ot_shape_planner_t *plan)
 {
   /* Uniscribe does not apply 'kern'. */
   if (hb_options ().uniscribe_bug_compatible)
     plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
 
+  /* 'calt' is enabled by default in hb-ot-shape.cc, but is a discretionary,
+     non-default feature for Indic scripts. */
+  plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
+
   plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 }
 
 
 struct would_substitute_feature_t
 {
   inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
   {
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
@@ -99,27 +99,16 @@ collect_features_myanmar (hb_ot_shape_pl
   for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
     map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
 }
 
 static void
 override_features_myanmar (hb_ot_shape_planner_t *plan)
 {
   plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
-
-  /*
-   * Note:
-   *
-   * Spec says 'mark' is used, and the mmrtext.ttf font from
-   * Windows 8 has lookups for it.  But testing suggests that
-   * Windows 8 Uniscribe is NOT applying it.  It *is* applying
-   * 'mkmk' however.
-   */
-  if (hb_options ().uniscribe_bug_compatible)
-    plan->map.add_feature (HB_TAG('m','a','r','k'), 0, F_GLOBAL);
 }
 
 
 enum syllable_type_t {
   consonant_syllable,
   broken_cluster,
   non_myanmar_cluster,
 };
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -156,16 +156,18 @@ hb_ot_shape_complex_categorize (const hb
   switch ((hb_tag_t) planner->props.script)
   {
     default:
       return &_hb_ot_complex_shaper_default;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
+
+    /* Unicode-3.0 additions */
     case HB_SCRIPT_MONGOLIAN:
     case HB_SCRIPT_SYRIAC:
 
     /* Unicode-5.0 additions */
     case HB_SCRIPT_NKO:
     case HB_SCRIPT_PHAGS_PA:
 
     /* Unicode-6.0 additions */
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc
@@ -415,17 +415,18 @@ void
 _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
 			    hb_font_t *font,
 			    hb_buffer_t  *buffer)
 {
   unsigned int count = buffer->len;
   hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
 					      HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
 
-  OT::hb_apply_context_t c (1, font, buffer, kern_mask, true/*auto_zwj*/);
+  OT::hb_apply_context_t c (1, font, buffer);
+  c.set_lookup_mask (kern_mask);
   c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
 
   for (buffer->idx = 0; buffer->idx < count;)
   {
     OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, buffer->idx, 1);
     if (!skippy_iter.next ())
     {
       buffer->idx++;
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -212,18 +212,34 @@ decompose_current_character (const hb_ot
 
 static inline void
 handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
 {
   hb_buffer_t * const buffer = c->buffer;
   for (; buffer->idx < end - 1;) {
     if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
       /* The next two lines are some ugly lines... But work. */
-      c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index());
-      buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+      if (c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      {
+	buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+      }
+      else
+      {
+        /* Just pass on the two characters separately, let GSUB do its magic. */
+	set_glyph (buffer->cur(), c->font);
+	buffer->next_glyph ();
+	set_glyph (buffer->cur(), c->font);
+	buffer->next_glyph ();
+      }
+      /* Skip any further variation selectors. */
+      while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+      {
+	set_glyph (buffer->cur(), c->font);
+	buffer->next_glyph ();
+      }
     } else {
       set_glyph (buffer->cur(), c->font);
       buffer->next_glyph ();
     }
   }
   if (likely (buffer->idx < end)) {
     set_glyph (buffer->cur(), c->font);
     buffer->next_glyph ();
--- a/gfx/harfbuzz/src/hb-ot-shape-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh
@@ -25,18 +25,17 @@
  */
 
 #ifndef HB_OT_SHAPE_PRIVATE_HH
 #define HB_OT_SHAPE_PRIVATE_HH
 
 #include "hb-private.hh"
 
 #include "hb-ot-map-private.hh"
-
-
+#include "hb-ot-layout-private.hh"
 
 
 
 struct hb_ot_shape_plan_t
 {
   hb_segment_properties_t props;
   const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -53,27 +53,18 @@ static hb_tag_t common_features[] = {
 static hb_tag_t horizontal_features[] = {
   HB_TAG('c','a','l','t'),
   HB_TAG('c','l','i','g'),
   HB_TAG('c','u','r','s'),
   HB_TAG('k','e','r','n'),
   HB_TAG('r','c','l','t'),
 };
 
-/* Note:
- * Technically speaking, vrt2 and vert are mutually exclusive.
- * According to the spec, valt and vpal are also mutually exclusive.
- * But we apply them all for now.
- */
 static hb_tag_t vertical_features[] = {
-  HB_TAG('v','a','l','t'),
   HB_TAG('v','e','r','t'),
-  HB_TAG('v','k','r','n'),
-  HB_TAG('v','p','a','l'),
-  HB_TAG('v','r','t','2'),
 };
 
 
 
 static void
 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      const hb_segment_properties_t  *props,
 			      const hb_feature_t             *user_features,
@@ -422,31 +413,36 @@ zero_mark_widths_by_gdef (hb_buffer_t *b
       buffer->pos[i].x_advance = 0;
       buffer->pos[i].y_advance = 0;
     }
 }
 
 static inline void
 hb_ot_position_default (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_position_start (c->font, c->buffer);
-
   unsigned int count = c->buffer->len;
   for (unsigned int i = 0; i < count; i++)
   {
     c->font->get_glyph_advance_for_direction (c->buffer->info[i].codepoint,
 					      c->buffer->props.direction,
 					      &c->buffer->pos[i].x_advance,
 					      &c->buffer->pos[i].y_advance);
     c->font->subtract_glyph_origin_for_direction (c->buffer->info[i].codepoint,
 						  c->buffer->props.direction,
 						  &c->buffer->pos[i].x_offset,
 						  &c->buffer->pos[i].y_offset);
 
   }
+}
+
+static inline bool
+hb_ot_position_complex (hb_ot_shape_context_t *c)
+{
+  bool ret = false;
+  unsigned int count = c->buffer->len;
 
   switch (c->plan->shaper->zero_width_marks)
   {
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
       zero_mark_widths_by_gdef (c->buffer);
       break;
 
     /* Not currently used for any shaper:
@@ -456,23 +452,16 @@ hb_ot_position_default (hb_ot_shape_cont
     */
 
     default:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
       break;
   }
-}
-
-static inline bool
-hb_ot_position_complex (hb_ot_shape_context_t *c)
-{
-  bool ret = false;
-  unsigned int count = c->buffer->len;
 
   if (hb_ot_layout_has_positioning (c->face))
   {
     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
 
     for (unsigned int i = 0; i < count; i++) {
       c->font->add_glyph_origin_for_direction (c->buffer->info[i].codepoint,
 					       HB_DIRECTION_LTR,
@@ -504,28 +493,30 @@ hb_ot_position_complex (hb_ot_shape_cont
 
     default:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
     //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
     case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
       break;
   }
 
-  hb_ot_layout_position_finish (c->font, c->buffer);
-
   return ret;
 }
 
 static inline void
 hb_ot_position (hb_ot_shape_context_t *c)
 {
+  hb_ot_layout_position_start (c->font, c->buffer);
+
   hb_ot_position_default (c);
 
   hb_bool_t fallback = !hb_ot_position_complex (c);
 
+  hb_ot_layout_position_finish (c->font, c->buffer);
+
   if (fallback && c->plan->shaper->fallback_position)
     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
 
   if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
     hb_buffer_reverse (c->buffer);
 
   /* Visual fallback goes here. */
 
@@ -537,32 +528,52 @@ hb_ot_position (hb_ot_shape_context_t *c
 /* Post-process */
 
 static void
 hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
 {
   if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
     return;
 
-  hb_codepoint_t space = 0;
+  hb_codepoint_t space;
+  enum {
+    SPACE_DONT_KNOW,
+    SPACE_AVAILABLE,
+    SPACE_UNAVAILABLE
+  } space_status = SPACE_DONT_KNOW;
 
   unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
+  unsigned int j = 0;
   for (unsigned int i = 0; i < count; i++)
-    if (unlikely (!is_a_ligature (c->buffer->info[i]) &&
-		  _hb_glyph_info_is_default_ignorable (&c->buffer->info[i])))
+  {
+    if (unlikely (!is_a_ligature (info[i]) &&
+		  _hb_glyph_info_is_default_ignorable (&info[i])))
     {
-      if (!space) {
-        /* We assume that the space glyph is not gid0. */
-        if (unlikely (!c->font->get_glyph (' ', 0, &space)) || !space)
-	return; /* No point! */
+      if (space_status == SPACE_DONT_KNOW)
+	space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
+
+      if (space_status == SPACE_AVAILABLE)
+      {
+	info[i].codepoint = space;
+	pos[i].x_advance = 0;
+	pos[i].y_advance = 0;
       }
-      c->buffer->info[i].codepoint = space;
-      c->buffer->pos[i].x_advance = 0;
-      c->buffer->pos[i].y_advance = 0;
+      else
+	continue; /* Delete it. */
     }
+    if (j != i)
+    {
+      info[j] = info[i];
+      pos[j] = pos[i];
+    }
+    j++;
+  }
+  c->buffer->len = j;
 }
 
 
 /* Pull it all together! */
 
 static void
 hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -316,24 +316,32 @@ struct hb_prealloced_array_t
     array = new_array;
     allocated = new_allocated;
     return &array[len++];
   }
 
   inline void pop (void)
   {
     len--;
-    /* TODO: shrink array if needed */
+  }
+
+  inline void remove (unsigned int i)
+  {
+     if (unlikely (i >= len))
+       return;
+     memmove (static_cast<void *> (&array[i]),
+	      static_cast<void *> (&array[i + 1]),
+	      (len - i - 1) * sizeof (Type));
+     len--;
   }
 
   inline void shrink (unsigned int l)
   {
      if (l < len)
        len = l;
-    /* TODO: shrink array if needed */
   }
 
   template <typename T>
   inline Type *find (T v) {
     for (unsigned int i = 0; i < len; i++)
       if (array[i] == v)
 	return &array[i];
     return NULL;
@@ -371,17 +379,17 @@ struct hb_prealloced_array_t
   {
     if (array != static_array)
       free (array);
     array = NULL;
     allocated = len = 0;
   }
 };
 
-#define HB_AUTO_ARRAY_PREALLOCED 64
+#define HB_AUTO_ARRAY_PREALLOCED 16
 template <typename Type>
 struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED>
 {
   hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); }
   ~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); }
 };
 
 
@@ -558,18 +566,18 @@ static inline unsigned char TOLOWER (uns
 
 static inline bool
 _hb_debug (unsigned int level,
 	   unsigned int max_level)
 {
   return level < max_level;
 }
 
-#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
-#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
+#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
 
 template <int max_level> static inline void
 _hb_debug_msg_va (const char *what,
 		  const void *obj,
 		  const char *func,
 		  bool indented,
 		  unsigned int level,
 		  int level_dir,
@@ -590,17 +598,17 @@ template <int max_level> static inline v
 /* One may want to add ASCII version of these.  See:
  * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
 #define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
 #define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
 #define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
 #define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
 #define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
     static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
-    fprintf (stderr, "%2d %s" VRBAR "%s",
+    fprintf (stderr, "%2u %s" VRBAR "%s",
 	     level,
 	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
 	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
   } else
     fprintf (stderr, "   " VRBAR LBAR);
 
   if (func)
   {
--- a/gfx/harfbuzz/src/hb-set-private.hh
+++ b/gfx/harfbuzz/src/hb-set-private.hh
@@ -40,53 +40,55 @@
  * queries.  As a result, our filters have much higher.
  */
 
 template <typename mask_t, unsigned int shift>
 struct hb_set_digest_lowest_bits_t
 {
   ASSERT_POD ();
 
+  static const unsigned int mask_bytes = sizeof (mask_t);
+  static const unsigned int mask_bits = sizeof (mask_t) * 8;
   static const unsigned int num_bits = 0
-				     + (sizeof (mask_t) >= 1 ? 3 : 0)
-				     + (sizeof (mask_t) >= 2 ? 1 : 0)
-				     + (sizeof (mask_t) >= 4 ? 1 : 0)
-				     + (sizeof (mask_t) >= 8 ? 1 : 0)
-				     + (sizeof (mask_t) >= 16? 1 : 0)
+				     + (mask_bytes >= 1 ? 3 : 0)
+				     + (mask_bytes >= 2 ? 1 : 0)
+				     + (mask_bytes >= 4 ? 1 : 0)
+				     + (mask_bytes >= 8 ? 1 : 0)
+				     + (mask_bytes >= 16? 1 : 0)
 				     + 0;
 
   ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
   ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
 
   inline void init (void) {
     mask = 0;
   }
 
   inline void add (hb_codepoint_t g) {
     mask |= mask_for (g);
   }
 
   inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
-    if ((b >> shift) - (a >> shift) >= sizeof (mask_t) * 8 - 1)
+    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
       mask = (mask_t) -1;
     else {
       mask_t ma = mask_for (a);
       mask_t mb = mask_for (b);
       mask |= mb + (mb - ma) - (mb < ma);
     }
   }
 
   inline bool may_have (hb_codepoint_t g) const {
     return !!(mask & mask_for (g));
   }
 
   private:
 
   static inline mask_t mask_for (hb_codepoint_t g) {
-    return ((mask_t) 1) << ((g >> shift) & (sizeof (mask_t) * 8 - 1));
+    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
   }
   mask_t mask;
 };
 
 template <typename head_t, typename tail_t>
 struct hb_set_digest_combiner_t
 {
   ASSERT_POD ();
@@ -164,17 +166,17 @@ struct hb_set_t
     for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
       if (elts[i])
         return false;
     return true;
   }
   inline void add (hb_codepoint_t g)
   {
     if (unlikely (in_error)) return;
-    if (unlikely (g == SENTINEL)) return;
+    if (unlikely (g == INVALID)) return;
     if (unlikely (g > MAX_G)) return;
     elt (g) |= mask (g);
   }
   inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
   {
     if (unlikely (in_error)) return;
     /* TODO Speedup */
     for (unsigned int i = a; i < b + 1; i++)
@@ -249,38 +251,44 @@ struct hb_set_t
   inline void invert (void)
   {
     if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] = ~elts[i];
   }
   inline bool next (hb_codepoint_t *codepoint) const
   {
-    if (unlikely (*codepoint == SENTINEL)) {
+    if (unlikely (*codepoint == INVALID)) {
       hb_codepoint_t i = get_min ();
-      if (i != SENTINEL) {
+      if (i != INVALID) {
         *codepoint = i;
 	return true;
-      } else
+      } else {
+	*codepoint = INVALID;
         return false;
+      }
     }
     for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
       if (has (i)) {
         *codepoint = i;
 	return true;
       }
+    *codepoint = INVALID;
     return false;
   }
   inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
   {
     hb_codepoint_t i;
 
     i = *last;
     if (!next (&i))
+    {
+      *last = *first = INVALID;
       return false;
+    }
 
     *last = *first = i;
     while (next (&i) && i == *last + 1)
       (*last)++;
 
     return true;
   }
 
@@ -293,35 +301,35 @@ struct hb_set_t
   }
   inline hb_codepoint_t get_min (void) const
   {
     for (unsigned int i = 0; i < ELTS; i++)
       if (elts[i])
 	for (unsigned int j = 0; j < BITS; j++)
 	  if (elts[i] & (1 << j))
 	    return i * BITS + j;
-    return SENTINEL;
+    return INVALID;
   }
   inline hb_codepoint_t get_max (void) const
   {
     for (unsigned int i = ELTS; i; i--)
       if (elts[i - 1])
 	for (unsigned int j = BITS; j; j--)
 	  if (elts[i - 1] & (1 << (j - 1)))
 	    return (i - 1) * BITS + (j - 1);
-    return SENTINEL;
+    return INVALID;
   }
 
   typedef uint32_t elt_t;
   static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */
   static const unsigned int SHIFT = 5;
   static const unsigned int BITS = (1 << SHIFT);
   static const unsigned int MASK = BITS - 1;
   static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
-  static  const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1;
+  static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
   elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
   elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
   elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
 
   elt_t elts[ELTS]; /* XXX 8kb */
 
   ASSERT_STATIC (sizeof (elt_t) * 8 == BITS);
--- a/gfx/harfbuzz/src/hb-set.cc
+++ b/gfx/harfbuzz/src/hb-set.cc
@@ -25,203 +25,447 @@
  */
 
 #include "hb-set-private.hh"
 
 
 /* Public API */
 
 
+/**
+ * hb_set_create: (Xconstructor)
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
 hb_set_create (void)
 {
   hb_set_t *set;
 
   if (!(set = hb_object_create<hb_set_t> ()))
     return hb_set_get_empty ();
 
   set->clear ();
 
   return set;
 }
 
+/**
+ * hb_set_get_empty:
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
 hb_set_get_empty (void)
 {
   static const hb_set_t _hb_set_nil = {
     HB_OBJECT_HEADER_STATIC,
     true, /* in_error */
 
     {0} /* elts */
   };
 
   return const_cast<hb_set_t *> (&_hb_set_nil);
 }
 
+/**
+ * hb_set_reference: (skip)
+ * @set: a set.
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
 hb_set_reference (hb_set_t *set)
 {
   return hb_object_reference (set);
 }
 
+/**
+ * hb_set_destroy: (skip)
+ * @set: a set.
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_destroy (hb_set_t *set)
 {
   if (!hb_object_destroy (set)) return;
 
   set->fini ();
 
   free (set);
 }
 
+/**
+ * hb_set_set_user_data: (skip)
+ * @set: a set.
+ * @key:
+ * @data:
+ * @destroy (closure data):
+ * @replace:
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_set_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key,
 		      void *              data,
 		      hb_destroy_func_t   destroy,
 		      hb_bool_t           replace)
 {
   return hb_object_set_user_data (set, key, data, destroy, replace);
 }
 
+/**
+ * hb_set_get_user_data: (skip)
+ * @set: a set.
+ * @key:
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 void *
 hb_set_get_user_data (hb_set_t           *set,
 		      hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (set, key);
 }
 
 
+/**
+ * hb_set_allocation_successful:
+ * @set: a set.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_allocation_successful (const hb_set_t  *set HB_UNUSED)
 {
   return !set->in_error;
 }
 
+/**
+ * hb_set_clear:
+ * @set: a set.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_clear (hb_set_t *set)
 {
   set->clear ();
 }
 
+/**
+ * hb_set_is_empty:
+ * @set: a set.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_is_empty (const hb_set_t *set)
 {
   return set->is_empty ();
 }
 
+/**
+ * hb_set_has:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_has (const hb_set_t *set,
 	    hb_codepoint_t  codepoint)
 {
   return set->has (codepoint);
 }
 
+/**
+ * hb_set_add:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_add (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
   set->add (codepoint);
 }
 
+/**
+ * hb_set_add_range:
+ * @set: a set.
+ * @first: 
+ * @last: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_add_range (hb_set_t       *set,
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
   set->add_range (first, last);
 }
 
+/**
+ * hb_set_del:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_del (hb_set_t       *set,
 	    hb_codepoint_t  codepoint)
 {
   set->del (codepoint);
 }
 
+/**
+ * hb_set_del_range:
+ * @set: a set.
+ * @first: 
+ * @last: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_del_range (hb_set_t       *set,
 		  hb_codepoint_t  first,
 		  hb_codepoint_t  last)
 {
   set->del_range (first, last);
 }
 
+/**
+ * hb_set_is_equal:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_is_equal (const hb_set_t *set,
 		 const hb_set_t *other)
 {
   return set->is_equal (other);
 }
 
+/**
+ * hb_set_set:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_set (hb_set_t       *set,
 	    const hb_set_t *other)
 {
   set->set (other);
 }
 
+/**
+ * hb_set_union:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_union (hb_set_t       *set,
 	      const hb_set_t *other)
 {
   set->union_ (other);
 }
 
+/**
+ * hb_set_intersect:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_intersect (hb_set_t       *set,
 		  const hb_set_t *other)
 {
   set->intersect (other);
 }
 
+/**
+ * hb_set_subtract:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_subtract (hb_set_t       *set,
 		 const hb_set_t *other)
 {
   set->subtract (other);
 }
 
+/**
+ * hb_set_symmetric_difference:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_symmetric_difference (hb_set_t       *set,
 			     const hb_set_t *other)
 {
   set->symmetric_difference (other);
 }
 
+/**
+ * hb_set_invert:
+ * @set: a set.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_invert (hb_set_t *set)
 {
   set->invert ();
 }
 
+/**
+ * hb_set_get_population:
+ * @set: a set.
+ *
+ * Returns the number of numbers in the set.
+ *
+ * Return value: set population.
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_set_get_population (const hb_set_t *set)
 {
   return set->get_population ();
 }
 
+/**
+ * hb_set_get_min:
+ * @set: a set.
+ *
+ * Finds the minimum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
 hb_codepoint_t
 hb_set_get_min (const hb_set_t *set)
 {
   return set->get_min ();
 }
 
+/**
+ * hb_set_get_max:
+ * @set: a set.
+ *
+ * Finds the maximum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
 hb_codepoint_t
 hb_set_get_max (const hb_set_t *set)
 {
   return set->get_max ();
 }
 
+/**
+ * hb_set_next:
+ * @set: a set.
+ * @codepoint: (inout):
+ *
+ * 
+ *
+ * Return value: whether there was a next value.
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_next (const hb_set_t *set,
 	     hb_codepoint_t *codepoint)
 {
   return set->next (codepoint);
 }
 
+/**
+ * hb_set_next_range:
+ * @set: a set.
+ * @first: (out): output first codepoint in the range.
+ * @last: (inout): input current last and output last codepoint in the range.
+ *
+ * Gets the next consecutive range of numbers in @set that
+ * are greater than current value of @last.
+ *
+ * Return value: whether there was a next range.
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_set_next_range (const hb_set_t *set,
 		   hb_codepoint_t *first,
 		   hb_codepoint_t *last)
 {
   return set->next_range (first, last);
 }
--- a/gfx/harfbuzz/src/hb-set.h
+++ b/gfx/harfbuzz/src/hb-set.h
@@ -31,16 +31,18 @@
 #ifndef HB_SET_H
 #define HB_SET_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
+#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
 typedef struct hb_set_t hb_set_t;
 
 
 hb_set_t *
 hb_set_create (void);
 
 hb_set_t *
 hb_set_get_empty (void);
--- a/gfx/harfbuzz/src/hb-shape-plan.cc
+++ b/gfx/harfbuzz/src/hb-shape-plan.cc
@@ -78,16 +78,30 @@ hb_shape_plan_plan (hb_shape_plan_t    *
 #undef HB_SHAPER_PLAN
 }
 
 
 /*
  * hb_shape_plan_t
  */
 
+/**
+ * hb_shape_plan_create: (Xconstructor)
+ * @face: 
+ * @props: 
+ * @user_features: (array length=num_user_features):
+ * @num_user_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_create (hb_face_t                     *face,
 		      const hb_segment_properties_t *props,
 		      const hb_feature_t            *user_features,
 		      unsigned int                   num_user_features,
 		      const char * const            *shaper_list)
 {
   assert (props->direction != HB_DIRECTION_INVALID);
@@ -106,16 +120,25 @@ hb_shape_plan_create (hb_face_t         
   shape_plan->face = hb_face_reference (face);
   shape_plan->props = *props;
 
   hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
 
   return shape_plan;
 }
 
+/**
+ * hb_shape_plan_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_get_empty (void)
 {
   static const hb_shape_plan_t _hb_shape_plan_nil = {
     HB_OBJECT_HEADER_STATIC,
 
     true, /* default_shaper_list */
     NULL, /* face */
@@ -129,54 +152,111 @@ hb_shape_plan_get_empty (void)
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
     }
   };
 
   return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
 }
 
+/**
+ * hb_shape_plan_reference: (skip)
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
 {
   return hb_object_reference (shape_plan);
 }
 
+/**
+ * hb_shape_plan_destroy: (skip)
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
 {
   if (!hb_object_destroy (shape_plan)) return;
 
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 
   hb_face_destroy (shape_plan->face);
 
   free (shape_plan);
 }
 
+/**
+ * hb_shape_plan_set_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
 			     hb_user_data_key_t *key,
 			     void *              data,
 			     hb_destroy_func_t   destroy,
 			     hb_bool_t           replace)
 {
   return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
 }
 
+/**
+ * hb_shape_plan_get_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 void *
 hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
 			     hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (shape_plan, key);
 }
 
 
+/**
+ * hb_shape_plan_execute:
+ * @shape_plan: a shape plan.
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
 		       hb_font_t          *font,
 		       hb_buffer_t        *buffer,
 		       const hb_feature_t *features,
 		       unsigned int        num_features)
 {
   if (unlikely (hb_object_is_inert (shape_plan) ||
@@ -233,16 +313,30 @@ static hb_bool_t
 hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
 		       const hb_shape_plan_proposal_t *proposal)
 {
   return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
 	 ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
 	  (shape_plan->shaper_func == proposal->shaper_func));
 }
 
+/**
+ * hb_shape_plan_create_cached:
+ * @face: 
+ * @props: 
+ * @user_features: (array length=num_user_features):
+ * @num_user_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_shape_plan_t *
 hb_shape_plan_create_cached (hb_face_t                     *face,
 			     const hb_segment_properties_t *props,
 			     const hb_feature_t            *user_features,
 			     unsigned int                   num_user_features,
 			     const char * const            *shaper_list)
 {
   if (num_user_features)
@@ -302,13 +396,23 @@ retry:
   }
 
   /* Release our reference on face. */
   hb_face_destroy (face);
 
   return hb_shape_plan_reference (shape_plan);
 }
 
+/**
+ * hb_shape_plan_get_shaper:
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
 {
   return shape_plan->shaper_name;
 }
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -148,26 +148,48 @@ parse_one_feature (const char **pp, cons
 {
   return parse_feature_value_prefix (pp, end, feature) &&
 	 parse_feature_tag (pp, end, feature) &&
 	 parse_feature_indices (pp, end, feature) &&
 	 parse_feature_value_postfix (pp, end, feature) &&
 	 *pp == end;
 }
 
+/**
+ * hb_feature_from_string:
+ * @str: (array length=len):
+ * @len: 
+ * @feature: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_feature_from_string (const char *str, int len,
 			hb_feature_t *feature)
 {
   if (len < 0)
     len = strlen (str);
 
   return parse_one_feature (&str, str + len, feature);
 }
 
+/**
+ * hb_feature_to_string:
+ * @feature: 
+ * @buf: (array length=size):
+ * @size: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_feature_to_string (hb_feature_t *feature,
 		      char *buf, unsigned int size)
 {
   if (unlikely (!size)) return;
 
   char s[128];
   unsigned int len = 0;
@@ -176,44 +198,53 @@ hb_feature_to_string (hb_feature_t *feat
   hb_tag_to_string (feature->tag, s + len);
   len += 4;
   while (len && s[len - 1] == ' ')
     len--;
   if (feature->start != 0 || feature->end != (unsigned int) -1)
   {
     s[len++] = '[';
     if (feature->start)
-      len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start);
+      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->start));
     if (feature->end != feature->start + 1) {
       s[len++] = ':';
       if (feature->end != (unsigned int) -1)
-	len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end);
+	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->end));
     }
     s[len++] = ']';
   }
   if (feature->value > 1)
   {
     s[len++] = '=';
-    len += snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value);
+    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%d", feature->value));
   }
   assert (len < ARRAY_LENGTH (s));
   len = MIN (len, size - 1);
   memcpy (buf, s, len);
-  s[len] = '\0';
+  buf[len] = '\0';
 }
 
 
 static const char **static_shaper_list;
 
 static inline
 void free_static_shaper_list (void)
 {
   free (static_shaper_list);
 }
 
+/**
+ * hb_shape_list_shapers:
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 const char **
 hb_shape_list_shapers (void)
 {
 retry:
   const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
 
   if (unlikely (!shaper_list))
   {
@@ -239,16 +270,30 @@ retry:
     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
 #endif
   }
 
   return shaper_list;
 }
 
 
+/**
+ * hb_shape_full:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_shape_full (hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features,
 	       const char * const *shaper_list)
 {
   if (unlikely (!buffer->len))
@@ -260,16 +305,27 @@ hb_shape_full (hb_font_t          *font,
   hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
   hb_shape_plan_destroy (shape_plan);
 
   if (res)
     buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
   return res;
 }
 
+/**
+ * hb_shape:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_shape (hb_font_t           *font,
 	  hb_buffer_t         *buffer,
 	  const hb_feature_t  *features,
 	  unsigned int         num_features)
 {
   hb_shape_full (font, buffer, features, num_features, NULL);
 }
--- a/gfx/harfbuzz/src/hb-ucdn.cc
+++ b/gfx/harfbuzz/src/hb-ucdn.cc
@@ -44,17 +44,17 @@ static const hb_script_t ucdn_script_tra
     HB_SCRIPT_THAI,
     HB_SCRIPT_LAO,
     HB_SCRIPT_TIBETAN,
     HB_SCRIPT_MYANMAR,
     HB_SCRIPT_GEORGIAN,
     HB_SCRIPT_HANGUL,
     HB_SCRIPT_ETHIOPIC,
     HB_SCRIPT_CHEROKEE,
-    HB_SCRIPT_CANADIAN_ABORIGINAL,
+    HB_SCRIPT_CANADIAN_SYLLABICS,
     HB_SCRIPT_OGHAM,
     HB_SCRIPT_RUNIC,
     HB_SCRIPT_KHMER,
     HB_SCRIPT_MONGOLIAN,
     HB_SCRIPT_HIRAGANA,
     HB_SCRIPT_KATAKANA,
     HB_SCRIPT_BOPOMOFO,
     HB_SCRIPT_HAN,
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -123,16 +123,19 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
   }
 
   /* Default_Ignorable codepoints:
    *
    * Note that as of Oct 2012 (Unicode 6.2), U+180E MONGOLIAN VOWEL SEPARATOR
    * is NOT Default_Ignorable, but it really behaves in a way that it should
    * be.  That has been reported to the Unicode Technical Committee for
    * consideration.  As such, we include it here, since Uniscribe removes it.
+   * It *is* in Unicode 6.3 however.  U+061C ARABIC LETTER MARK from Unicode
+   * 6.3 is also added manually.  The new Unicode 6.3 bidi formatting
+   * characters are encoded in a block that was Default_Ignorable already.
    *
    * Note: While U+115F and U+1160 are Default_Ignorable, we do NOT want to
    * hide them, as the way Uniscribe has implemented them is with regular
    * spacing glyphs, and that's the way fonts are made to work.  As such,
    * we make exceptions for those two.
    *
    * Gathered from:
    * http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on
@@ -168,16 +171,17 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIM
     hb_codepoint_t plane = ch >> 16;
     if (likely (plane == 0))
     {
       /* BMP */
       hb_codepoint_t page = ch >> 8;
       switch (page) {
 	case 0x00: return unlikely (ch == 0x00AD);
 	case 0x03: return unlikely (ch == 0x034F);
+	case 0x06: return unlikely (ch == 0x061C);
 	case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5);
 	case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E);
 	case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,
 							    0x202A, 0x202E,
 							    0x2060, 0x206F);
 	case 0x31: return unlikely (ch == 0x3164);
 	case 0xFE: return hb_in_range<hb_codepoint_t> (ch, 0xFE00, 0xFE0F) || ch == 0xFEFF;
 	case 0xFF: return hb_in_range<hb_codepoint_t> (ch, 0xFFF0, 0xFFF8) || ch == 0xFFA0;
--- a/gfx/harfbuzz/src/hb-unicode.cc
+++ b/gfx/harfbuzz/src/hb-unicode.cc
@@ -128,33 +128,43 @@ HB_UNICODE_FUNCS_IMPLEMENT_SET
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_default (void)
 {
 #define HB_UNICODE_FUNCS_IMPLEMENT(set) \
   return hb_##set##_get_unicode_funcs ();
 
 #ifdef HAVE_GLIB
   HB_UNICODE_FUNCS_IMPLEMENT(glib)
-#elif defined(HAVE_ICU)
+#elif 0 && defined(HAVE_ICU)
   HB_UNICODE_FUNCS_IMPLEMENT(icu)
 #elif defined(HAVE_UCDN)
   HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
 #else
 #define HB_UNICODE_FUNCS_NIL 1
   HB_UNICODE_FUNCS_IMPLEMENT(nil)
 #endif
 
 #undef HB_UNICODE_FUNCS_IMPLEMENT
 }
 
 #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
 #pragma message("Could not find any Unicode functions implementation, you have to provide your own.")
 #pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS.")
 #endif
 
+/**
+ * hb_unicode_funcs_create: (Xconstructor)
+ * @parent: (allow-none):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
 {
   hb_unicode_funcs_t *ufuncs;
 
   if (!(ufuncs = hb_object_create<hb_unicode_funcs_t> ()))
     return hb_unicode_funcs_get_empty ();
 
@@ -182,76 +192,156 @@ const hb_unicode_funcs_t _hb_unicode_fun
   true, /* immutable */
   {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil,
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
   }
 };
 
+/**
+ * hb_unicode_funcs_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty (void)
 {
   return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
 }
 
+/**
+ * hb_unicode_funcs_reference: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
 {
   return hb_object_reference (ufuncs);
 }
 
+/**
+ * hb_unicode_funcs_destroy: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
 {
   if (!hb_object_destroy (ufuncs)) return;
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
   if (ufuncs->destroy.name) ufuncs->destroy.name (ufuncs->user_data.name);
     HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
   hb_unicode_funcs_destroy (ufuncs->parent);
 
   free (ufuncs);
 }
 
+/**
+ * hb_unicode_funcs_set_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
 			        hb_user_data_key_t *key,
 			        void *              data,
 			        hb_destroy_func_t   destroy,
 				hb_bool_t           replace)
 {
   return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
 }
 
+/**
+ * hb_unicode_funcs_get_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
 			        hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (ufuncs, key);
 }
 
 
+/**
+ * hb_unicode_funcs_make_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
 {
   if (hb_object_is_inert (ufuncs))
     return;
 
   ufuncs->immutable = true;
 }
 
+/**
+ * hb_unicode_funcs_is_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
 {
   return ufuncs->immutable;
 }
 
+/**
+ * hb_unicode_funcs_get_parent:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
 {
   return ufuncs->parent ? ufuncs->parent : hb_unicode_funcs_get_empty ();
 }
 
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name)						\
@@ -289,34 +379,72 @@ return_type									\
 hb_unicode_##name (hb_unicode_funcs_t *ufuncs,					\
 		   hb_codepoint_t      unicode)					\
 {										\
   return ufuncs->name (unicode);						\
 }
 HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
+/**
+ * hb_unicode_compose:
+ * @ufuncs: Unicode functions.
+ * @a: 
+ * @b: 
+ * @ab: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
 		    hb_codepoint_t      a,
 		    hb_codepoint_t      b,
 		    hb_codepoint_t     *ab)
 {
   return ufuncs->compose (a, b, ab);
 }
 
+/**
+ * hb_unicode_decompose:
+ * @ufuncs: Unicode functions.
+ * @ab: 
+ * @a: (out):
+ * @b: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
 		      hb_codepoint_t      ab,
 		      hb_codepoint_t     *a,
 		      hb_codepoint_t     *b)
 {
   return ufuncs->decompose (ab, a, b);
 }
 
+/**
+ * hb_unicode_decompose_compatibility:
+ * @ufuncs: Unicode functions.
+ * @u: 
+ * @decomposed: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
 				    hb_codepoint_t      u,
 				    hb_codepoint_t     *decomposed)
 {
   return ufuncs->decompose_compatibility (u, decomposed);
 }
 
--- a/gfx/harfbuzz/src/hb-unicode.h
+++ b/gfx/harfbuzz/src/hb-unicode.h
@@ -243,17 +243,17 @@ typedef hb_bool_t			(*hb_unicode_compose
 typedef hb_bool_t			(*hb_unicode_decompose_func_t)		(hb_unicode_funcs_t *ufuncs,
 										 hb_codepoint_t      ab,
 										 hb_codepoint_t     *a,
 										 hb_codepoint_t     *b,
 										 void               *user_data);
 
 /**
  * hb_unicode_decompose_compatibility_func_t:
- * @ufuncs: Unicode function structure
+ * @ufuncs: a Unicode function structure
  * @u: codepoint to decompose
  * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
  * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
  *
  * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
  * The complete length of the decomposition will be returned.
  *
  * If @u has no compatibility decomposition, zero should be returned.
@@ -269,54 +269,142 @@ typedef unsigned int			(*hb_unicode_deco
 											 hb_codepoint_t     *decomposed,
 											 void               *user_data);
 
 /* See Unicode 6.1 for details on the maximum decomposition length. */
 #define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
 
 /* setters */
 
+/**
+ * hb_unicode_funcs_set_combining_class_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_combining_class_func_t combining_class_func,
+					   hb_unicode_combining_class_func_t func,
 					   void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
-					   hb_unicode_eastasian_width_func_t eastasian_width_func,
+					   hb_unicode_eastasian_width_func_t func,
 					   void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_general_category_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
-					    hb_unicode_general_category_func_t general_category_func,
+					    hb_unicode_general_category_func_t func,
 					    void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_mirroring_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
-				     hb_unicode_mirroring_func_t mirroring_func,
+				     hb_unicode_mirroring_func_t func,
 				     void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_script_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
-				  hb_unicode_script_func_t script_func,
+				  hb_unicode_script_func_t func,
 				  void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_compose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
-				   hb_unicode_compose_func_t compose_func,
+				   hb_unicode_compose_func_t func,
 				   void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_decompose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
-				     hb_unicode_decompose_func_t decompose_func,
+				     hb_unicode_decompose_func_t func,
 				     void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
-						   hb_unicode_decompose_compatibility_func_t decompose_compatibility_func,
+						   hb_unicode_decompose_compatibility_func_t func,
 						   void *user_data, hb_destroy_func_t destroy);
 
 /* accessors */
 
 hb_unicode_combining_class_t
 hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
 			    hb_codepoint_t unicode);
 
--- a/gfx/harfbuzz/src/hb-uniscribe.cc
+++ b/gfx/harfbuzz/src/hb-uniscribe.cc
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2011,2012  Google, Inc.
+ * Copyright © 2011,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -27,68 +27,441 @@
 #define _WIN32_WINNT 0x0600
 #define WIN32_LEAN_AND_MEAN
 
 #define HB_SHAPER uniscribe
 #include "hb-shaper-impl-private.hh"
 
 #include <windows.h>
 #include <usp10.h>
+#include <rpc.h>
 
 #include "hb-uniscribe.h"
 
+#include "hb-open-file-private.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-tag.h"
 
 
 #ifndef HB_DEBUG_UNISCRIBE
 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
 #endif
 
 
-/*
-DWORD GetFontData(
-  __in   HDC hdc,
-  __in   DWORD dwTable,
-  __in   DWORD dwOffset,
-  __out  LPVOID lpvBuffer,
-  __in   DWORD cbData
+typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
+  const WCHAR *pwcInChars,
+  int cInChars,
+  int cMaxItems,
+  const SCRIPT_CONTROL *psControl,
+  const SCRIPT_STATE *psState,
+  SCRIPT_ITEM *pItems,
+  OPENTYPE_TAG *pScriptTags,
+  int *pcItems
+);
+
+typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  int cChars,
+  int cMaxGlyphs,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  WORD *pwOutGlyphs,
+  SCRIPT_GLYPHPROP *pOutGlyphProps,
+  int *pcGlyphs
+);
+
+typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  int cChars,
+  const WORD *pwGlyphs,
+  const SCRIPT_GLYPHPROP *pGlyphProps,
+  int cGlyphs,
+  int *piAdvance,
+  GOFFSET *pGoffset,
+  ABC *pABC
 );
-*/
+
+
+/* Fallback implementations. */
+
+static HRESULT WINAPI
+hb_ScriptItemizeOpenType(
+  const WCHAR *pwcInChars,
+  int cInChars,
+  int cMaxItems,
+  const SCRIPT_CONTROL *psControl,
+  const SCRIPT_STATE *psState,
+  SCRIPT_ITEM *pItems,
+  OPENTYPE_TAG *pScriptTags,
+  int *pcItems
+)
+{
+{
+  return ScriptItemize (pwcInChars,
+			cInChars,
+			cMaxItems,
+			psControl,
+			psState,
+			pItems,
+			pcItems);
+}
+}
+
+static HRESULT WINAPI
+hb_ScriptShapeOpenType(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  int cChars,
+  int cMaxGlyphs,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  WORD *pwOutGlyphs,
+  SCRIPT_GLYPHPROP *pOutGlyphProps,
+  int *pcGlyphs
+)
+{
+  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
+  return ScriptShape (hdc,
+		      psc,
+		      pwcChars,
+		      cChars,
+		      cMaxGlyphs,
+		      psa,
+		      pwOutGlyphs,
+		      pwLogClust,
+		      psva,
+		      pcGlyphs);
+}
+
+static HRESULT WINAPI
+hb_ScriptPlaceOpenType(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,