bug 695857 - update harfbuzz code and adapt gfx/thebes for revised harfbuzz API. r=jdaggett
authorJonathan Kew <jfkthame@gmail.com>
Tue, 14 Feb 2012 08:03:01 +0000
changeset 86802 392319d8c1fada29709b6d561224e874dede2b45
parent 86801 91d77c934b264f3b93346aa113ad957e160074de
child 86803 b343b73149189a3c67167d6feeb3d54b8fc13b9e
push id22058
push usermak77@bonardo.net
push dateWed, 15 Feb 2012 16:38:33 +0000
treeherdermozilla-central@46e22ce549b0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett
bugs695857
milestone13.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 695857 - update harfbuzz code and adapt gfx/thebes for revised harfbuzz API. r=jdaggett harfbuzz library code from upstream harfbuzz-ng commit f51e167436a51b890ffe3f7f7920498fa287acd9; replaced HB_SCRIPT_* with MOZ_SCRIPT_* codes in gfx; adapted for changes to HB function signatures.
gfx/harfbuzz/COPYING
gfx/harfbuzz/Makefile.am
gfx/harfbuzz/README
gfx/harfbuzz/TODO
gfx/harfbuzz/autogen.sh
gfx/harfbuzz/configure.ac
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/Makefile.in
gfx/harfbuzz/src/check-c-linkage-decls.sh
gfx/harfbuzz/src/check-header-guards.sh
gfx/harfbuzz/src/check-includes.sh
gfx/harfbuzz/src/check-internal-symbols.sh
gfx/harfbuzz/src/check-libstdc++.sh
gfx/harfbuzz/src/gen-arabic-joining-table.py
gfx/harfbuzz/src/gen-arabic-table.py
gfx/harfbuzz/src/gen-indic-table.py
gfx/harfbuzz/src/hb-blob-private.h
gfx/harfbuzz/src/hb-blob.c
gfx/harfbuzz/src/hb-blob.cc
gfx/harfbuzz/src/hb-blob.h
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-buffer.h
gfx/harfbuzz/src/hb-common.c
gfx/harfbuzz/src/hb-common.cc
gfx/harfbuzz/src/hb-common.h
gfx/harfbuzz/src/hb-fallback-shape-private.hh
gfx/harfbuzz/src/hb-fallback-shape.cc
gfx/harfbuzz/src/hb-font-private.h
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-font.h
gfx/harfbuzz/src/hb-ft.c
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-ft.h
gfx/harfbuzz/src/hb-glib.c
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-glib.h
gfx/harfbuzz/src/hb-gobject-enums.cc.tmpl
gfx/harfbuzz/src/hb-gobject-structs.cc
gfx/harfbuzz/src/hb-gobject.h
gfx/harfbuzz/src/hb-graphite.cc
gfx/harfbuzz/src/hb-graphite.h
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-graphite2.h
gfx/harfbuzz/src/hb-icu.c
gfx/harfbuzz/src/hb-icu.cc
gfx/harfbuzz/src/hb-icu.h
gfx/harfbuzz/src/hb-language.c
gfx/harfbuzz/src/hb-language.h
gfx/harfbuzz/src/hb-mutex-private.hh
gfx/harfbuzz/src/hb-object-private.h
gfx/harfbuzz/src/hb-object-private.hh
gfx/harfbuzz/src/hb-open-file-private.hh
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-head-private.hh
gfx/harfbuzz/src/hb-ot-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-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-layout.h
gfx/harfbuzz/src/hb-ot-map-private.hh
gfx/harfbuzz/src/hb-ot-map.cc
gfx/harfbuzz/src/hb-ot-maxp-table.hh
gfx/harfbuzz/src/hb-ot-name-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.h
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-misc.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape-private.hh
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-ot-shape.h
gfx/harfbuzz/src/hb-ot-tag.c
gfx/harfbuzz/src/hb-ot-tag.cc
gfx/harfbuzz/src/hb-ot-tag.h
gfx/harfbuzz/src/hb-ot.h
gfx/harfbuzz/src/hb-private.h
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shape.h
gfx/harfbuzz/src/hb-tt-font.cc
gfx/harfbuzz/src/hb-unicode-private.h
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-unicode.c
gfx/harfbuzz/src/hb-unicode.cc
gfx/harfbuzz/src/hb-unicode.h
gfx/harfbuzz/src/hb-uniscribe.cc
gfx/harfbuzz/src/hb-uniscribe.h
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/hb-version.h.in
gfx/harfbuzz/src/hb.h
gfx/harfbuzz/src/main.cc
gfx/harfbuzz/src/test.c
gfx/harfbuzz/src/test.cc
gfx/thebes/Makefile.in
gfx/thebes/genUnicodeScriptData.pl
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxGraphiteShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.h
gfx/thebes/gfxMacFont.cpp
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxScriptItemizer.cpp
gfx/thebes/gfxScriptItemizer.h
gfx/thebes/gfxUnicodeProperties.cpp
gfx/thebes/gfxUnicodeProperties.h
gfx/thebes/gfxUnicodePropertyData.cpp
gfx/thebes/gfxUnicodeScriptCodes.h
--- a/gfx/harfbuzz/COPYING
+++ b/gfx/harfbuzz/COPYING
@@ -1,8 +1,22 @@
+HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
+
+Copyright © 2011 Codethink Limited
+Copyright © 2010,2011  Google, Inc.
+Copyright © 2006  Behdad Esfahbod
+Copyright © 2009  Keith Stribley
+Copyright © 2009  Martin Hosken and SIL International
+Copyright © 2007  Chris Wilson
+Copyright © 2004,2007,2008,2009,2010  Red Hat, Inc.
+Copyright © 1998-2004  David Turner and Werner Lemberg
+
+For full copyright notices consult the individual files in the package.
+
+
 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
--- a/gfx/harfbuzz/Makefile.am
+++ b/gfx/harfbuzz/Makefile.am
@@ -1,15 +1,21 @@
-SUBDIRS = src
+# Process this file with automake to produce Makefile.in
+
+NULL =
+
+SUBDIRS = src util test
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 
 EXTRA_DIST = \
-	autogen.sh
+	autogen.sh \
+	harfbuzz.doap \
+	$(NULL)
 
 MAINTAINERCLEANFILES = \
 	$(srcdir)/INSTALL \
 	$(srcdir)/aclocal.m4 \
 	$(srcdir)/autoscan.log \
 	$(srcdir)/compile \
 	$(srcdir)/config.guess \
 	$(srcdir)/config.h.in \
@@ -18,18 +24,21 @@ MAINTAINERCLEANFILES = \
 	$(srcdir)/depcomp \
 	$(srcdir)/install-sh \
 	$(srcdir)/ltmain.sh \
 	$(srcdir)/missing \
 	$(srcdir)/mkinstalldirs \
 	$(srcdir)/ChangeLog \
 	`find "$(srcdir)" -type f -name Makefile.in -print`
 
+
+#
+# ChangeLog generation
+#
 CHANGELOG_RANGE =
-
 ChangeLog: $(srcdir)/ChangeLog
 $(srcdir)/ChangeLog:
 	$(AM_V_GEN) if test -d "$(srcdir)/.git"; then \
 	  (GIT_DIR=$(top_srcdir)/.git ./missing --run \
 	   git log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
 	  && mv -f $@.tmp $@ \
 	  || ($(RM) $@.tmp; \
 	      echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
@@ -37,9 +46,34 @@ ChangeLog: $(srcdir)/ChangeLog
 	else \
 	  test -f $@ || \
 	  (echo A git checkout and git-log is required to generate ChangeLog >&2 && \
 	  echo A git checkout and git-log is required to generate this file >> $@); \
 	fi
 .PHONY: $(srcdir)/ChangeLog
 
 
+#
+# Release engineering
+#
+
+# TODO: Copy infrastructure from cairo
+
+TAR_OPTIONS = --owner=0 --group=0
+dist-hook: dist-clear-sticky-bits
+# Clean up any sticky bits we may inherit from parent dir
+dist-clear-sticky-bits:
+	chmod -R a-s $(distdir)
+
+
+tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.bz2
+sha256_file = $(tar_file).sha256
+gpg_file = $(sha256_file).asc
+$(sha256_file): $(tar_file)
+	sha256sum $^ > $@
+$(gpg_file): $(sha256_file)
+	@echo "Please enter your GPG password to sign the checksum."
+	gpg --armor --sign $^
+
+release-files: $(tar_file) $(sha256_file) $(gpg_file)
+
+
 -include $(top_srcdir)/git.mk
--- a/gfx/harfbuzz/README
+++ b/gfx/harfbuzz/README
@@ -1,9 +1,7 @@
 This is HarfBuzz, a text shaping library.
 
-Bug reports on these files should be sent to the HarfBuzz mailing list as
-listed on http://freedesktop.org/wiki/Software/harfbuzz
+For bug reports, mailing list, and other information please visit:
+
+  http://harfbuzz.org/
 
 For license information, see the file COPYING.
-
-Behdad Esfahbod
-May 24, 2009
--- a/gfx/harfbuzz/TODO
+++ b/gfx/harfbuzz/TODO
@@ -1,23 +1,85 @@
-- Rename get_table to reference_table
+General fixes:
+=============
+
+- Move feature parsing from util into the library
+
+- 'const' for getter APIs? (use mutable internally)
+
+- Fix TT 'kern' on/off and GPOS interaction (move kerning before GPOS)
 
-- Avoid allocating blob objects internally for for_data() faces
+- Do proper rounding when scaling from font space?
+
+- Misc features:
+  * init/medi/fina/isol for non-cursive scripts
+  * vkna,hkna etc for kana, *jmo for hangul, etc
+
+- Move non-native direction and normalization handling to the generic non-OT
+  layer, such that uniscribe and other backends can use.
+
+- Uniscribe backend needs to enforce one direction only, otherwise cluster
+  values can confused the user.
 
-- head table access cleanup (div by zero now!)
-- cache various expensive scale computation
+
+API issues to fix before 1.0:
+============================
+
+- Rename all internal symbols (static ones even) to have _hb prefix?
+
+- Add pkg-config files for glue codes (harfbuzz-glib, etc)
+
+- Figure out how many .so objects, how to link, etc
 
-- SFNT api?  get_num_faces?
+- Add hb-cairo glue
+
+- Add sanitize API (and a cached version, that saves result on blob user-data)
+
+- Add glib GBoxedType stuff and introspection
 
-- GNOME Bug 612402 - (hb-arm) HarfBuzz compilation fix for arm
+
+API to add (maybe after 1.0):
+============================
+
+- Add Uniscribe face / font get API
 
-- Make sure LangSys default feature is only applied once...
+- BCP 47 language handling / API (language_matches?)
+
+- Add hb_face_get_glyph_count()?
+
+- Add hb_font_create_linear()?
+
+- Add hb_shape_plan()/hb_shape_execute()
+
+- Add query API for aalt-like features?
 
-- kern/GPOS interaction
+- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
+
+- Add segmentation API
+
+- Add hb-fribidi?
+
+
+hb-view enhancements:
+====================
 
-- Use size_t in sanitize?
-- Better define HB_INTERNAL
-- Future-proof metrics struct
+- Add --format
+- Add --width, --height, --auto-size, --align, etc?
+- Port to GOption, --help
+- Add XML and JSON formats
+
+
+Tests to write:
+==============
+
+- ot-layout enumeration API (needs font)
 
-hb-ot:
-- Rename hb_internal_glyph_info_t to hb_ot_glyph_info_t
-- Add query API for aalt-like features
-- HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH vs LookupType::... mess
+- Finish test-shape.c, grep for TODO
+
+- Finish test-unicode.c, grep for TODO
+
+
+Optimizations:
+=============
+
+- Avoid allocating blob objects internally for for_data() faces?
+
+- Add caching layer to hb-ft
--- a/gfx/harfbuzz/autogen.sh
+++ b/gfx/harfbuzz/autogen.sh
@@ -1,185 +1,33 @@
 #!/bin/sh
 # Run this to generate all the initial makefiles, etc.
-set -e
-
-ARGV0=$0
 
-# Allow invocation from a separate build directory; in that case, we change
-# to the source directory to run the auto*, then change back before running configure
-srcdir=`dirname $ARGV0`
-test -z "$srcdir" && srcdir=.
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
 
-ORIGDIR=`pwd`
+olddir=`pwd`
 cd $srcdir
 
-PACKAGE=harfbuzz
-
-LIBTOOLIZE_FLAGS="--copy --force --automake"
-ACLOCAL_FLAGS=""
-AUTOHEADER=${AUTOHEADER-autoheader}
-GTKDOCIZE_FLAGS="--copy"
-GTKDOCIZE=${GTKDOCIZE-gtkdocize}
-AUTOMAKE_FLAGS="--add-missing --gnu -Wall"
-AUTOCONF=${AUTOCONF-autoconf}
-
-CONFIGURE_AC=
-test -f configure.ac && CONFIGURE_AC=configure.ac
-
-if test "X$CONFIGURE_AC" = X; then
-  echo "$ARGV0: ERROR: No $srcdir/configure.in or $srcdir/configure.ac found."
-  exit 1
-fi
-
-extract_version() {
-	grep "^ *$1" "$CONFIGURE_AC" | sed 's/.*(\[*\([^])]*\)]*).*/\1/'
-}
-
-autoconf_min_vers=`extract_version AC_PREREQ`
-automake_min_vers=`extract_version AM_INIT_AUTOMAKE`
-libtoolize_min_vers=`extract_version AC_PROG_LIBTOOL`
-aclocal_min_vers=$automake_min_vers
-
-
-# Not all echo versions allow -n, so we check what is possible. This test is
-# based on the one in autoconf.
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
-  *c*,-n*) ECHO_N= ;;
-  *c*,*  ) ECHO_N=-n ;;
-  *)       ECHO_N= ;;
-esac
-
-
-# some terminal codes ...
-boldface="`tput bold 2>/dev/null || true`"
-normal="`tput sgr0 2>/dev/null || true`"
-printbold() {
-    echo $ECHO_N "$boldface"
-    echo "$@"
-    echo $ECHO_N "$normal"
-}
-printerr() {
-    echo "$@" >&2
-}
-
-
-# Usage:
-#     compare_versions MIN_VERSION ACTUAL_VERSION
-# returns true if ACTUAL_VERSION >= MIN_VERSION
-compare_versions() {
-    ch_min_version=$1
-    ch_actual_version=$2
-    ch_status=0
-    IFS="${IFS=         }"; ch_save_IFS="$IFS"; IFS="."
-    set $ch_actual_version
-    for ch_min in $ch_min_version; do
-        ch_cur=`echo $1 | sed 's/[^0-9].*$//'`; shift # remove letter suffixes
-        if [ -z "$ch_min" ]; then break; fi
-        if [ -z "$ch_cur" ]; then ch_status=1; break; fi
-        if [ $ch_cur -gt $ch_min ]; then break; fi
-        if [ $ch_cur -lt $ch_min ]; then ch_status=1; break; fi
-    done
-    IFS="$ch_save_IFS"
-    return $ch_status
+echo -n "checking for ragel... "
+which ragel || {
+	echo "You need to install ragel... See http://www.complang.org/ragel/"
+	exit 1
 }
 
-# Usage:
-#     version_check PACKAGE VARIABLE CHECKPROGS MIN_VERSION SOURCE
-# checks to see if the package is available
-version_check() {
-    vc_package=$1
-    vc_variable=$2
-    vc_checkprogs=$3
-    vc_min_version=$4
-    vc_source=$5
-    vc_status=1
-
-    vc_checkprog=`eval echo "\\$$vc_variable"`
-    if [ -n "$vc_checkprog" ]; then
-	printbold "using $vc_checkprog for $vc_package"
-	return 0
-    fi
-
-    printbold "checking for $vc_package >= $vc_min_version..."
-    for vc_checkprog in $vc_checkprogs; do
-	echo $ECHO_N "  testing $vc_checkprog... "
-	if $vc_checkprog --version < /dev/null > /dev/null 2>&1; then
-	    vc_actual_version=`$vc_checkprog --version | head -n 1 | \
-                               sed 's/^.*[ 	]\([0-9.]*[a-z]*\).*$/\1/'`
-	    if compare_versions $vc_min_version $vc_actual_version; then
-		echo "found $vc_actual_version"
-		# set variable
-		eval "$vc_variable=$vc_checkprog"
-		vc_status=0
-		break
-	    else
-		echo "too old (found version $vc_actual_version)"
-	    fi
-	else
-	    echo "not found."
-	fi
-    done
-    if [ "$vc_status" != 0 ]; then
-	printerr "***Error***: You must have $vc_package >= $vc_min_version installed"
-	printerr "  to build $PROJECT.  Download the appropriate package for"
-	printerr "  from your distribution or get the source tarball at"
-        printerr "    $vc_source"
-	printerr
-    fi
-    return $vc_status
+echo -n "checking for pkg-config... "
+which pkg-config || {
+	echo "*** No pkg-config found, please install it ***"
+	exit 1
 }
 
-
-version_check autoconf AUTOCONF $AUTOCONF $autoconf_min_vers \
-    "http://ftp.gnu.org/pub/gnu/autoconf/autoconf-${autoconf_min_vers}.tar.gz" || DIE=1
-
-#
-# Hunt for an appropriate version of automake and aclocal; we can't
-# assume that 'automake' is necessarily the most recent installed version
-#
-# We check automake first to allow it to be a newer version than we know about.
-#
-version_check automake AUTOMAKE "$AUTOMAKE automake automake-1.10 automake-1.9 automake-1.8 automake-1.7" $automake_min_vers \
-    "http://ftp.gnu.org/pub/gnu/automake/automake-${automake_min_vers}.tar.gz" || DIE=1
-ACLOCAL=`echo $AUTOMAKE | sed s/automake/aclocal/`
-
-
-version_check libtool LIBTOOLIZE "$LIBTOOLIZE glibtoolize libtoolize" $libtoolize_min_vers \
-    "http://ftp.gnu.org/pub/gnu/libtool/libtool-${libtool_min_vers}.tar.gz" || DIE=1
-
-if test -n "$DIE"; then
-  exit 1
-fi
-
-
-if test -z "$*"; then
-  echo "$ARGV0:	Note: \`./configure' will be run with no arguments."
-  echo "		If you wish to pass any to it, please specify them on the"
-  echo "		\`$0' command line."
-  echo
-fi
-
-do_cmd() {
-    echo "$ARGV0: running \`$@'"
-    $@
+echo -n "checking for autoreconf... "
+which autoreconf || {
+	echo "*** No autoreconf found, please install it ***"
+	exit 1
 }
 
-do_cmd $LIBTOOLIZE $LIBTOOLIZE_FLAGS
-
-do_cmd $ACLOCAL $ACLOCAL_FLAGS
-
-do_cmd $AUTOHEADER
-
-touch ChangeLog
-
-#do_cmd $GTKDOCIZE $GTKDOCIZE_FLAGS
+echo "running autoreconf --force --install --verbose"
+autoreconf --force --install --verbose || exit $?
 
-do_cmd $AUTOMAKE $AUTOMAKE_FLAGS
-
-do_cmd $AUTOCONF
-
-cd "$ORIGDIR" || exit 1
-
-rm -f config.cache
-
-do_cmd $srcdir/configure \
-	${1+"$@"} && echo "Now type \`make' to compile $PROJECT." || exit 1
+cd $olddir
+echo "running configure $@"
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
--- a/gfx/harfbuzz/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,64 +1,189 @@
-AC_PREREQ(2.59)
-AC_INIT(harfbuzz, 0.2, [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz])
+AC_PREREQ([2.64])
+AC_INIT([harfbuzz],
+        [0.7.0],
+        [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz],
+        [harfbuzz],
+        [http://harfbuzz.org/])
+
 AC_CONFIG_SRCDIR([harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE([1.9.6 gnu dist-bzip2 no-dist-gzip -Wall no-define])
-m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
-AC_LIBTOOL_WIN32_DLL
-AC_PROG_LIBTOOL dnl ([1.4]) Don't remove!
+AM_INIT_AUTOMAKE([1.11.1 gnu dist-bzip2 no-dist-gzip -Wall no-define])
+AM_SILENT_RULES([yes])
 
+# Check for programs
 AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CXX
 
-AC_CHECK_FUNCS(mprotect sysconf getpagesize)
-AC_CHECK_HEADERS(unistd.h sys/mman.h)
+# Initialize libtool
+LT_PREREQ([2.2])
+LT_INIT([disable-static])
+
+# Version
+m4_define(hb_version_triplet,m4_split(AC_PACKAGE_VERSION,[[.]]))
+m4_define(hb_version_major,m4_argn(1,hb_version_triplet))
+m4_define(hb_version_minor,m4_argn(2,hb_version_triplet))
+m4_define(hb_version_micro,m4_argn(3,hb_version_triplet))
+HB_VERSION_MAJOR=hb_version_major
+HB_VERSION_MINOR=hb_version_minor
+HB_VERSION_MICRO=hb_version_micro
+HB_VERSION=AC_PACKAGE_VERSION
+AC_SUBST(HB_VERSION_MAJOR)
+AC_SUBST(HB_VERSION_MINOR)
+AC_SUBST(HB_VERSION_MICRO)
+AC_SUBST(HB_VERSION)
 
-# Make sure we don't link to libstdc++
+# Libtool version
+m4_define([hb_version_int],
+	  m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro))
+m4_if(m4_eval(hb_version_minor % 2), [1],
+      dnl for unstable releases
+      [m4_define([hb_libtool_revision], 0)],
+      dnl for stable releases
+      [m4_define([hb_libtool_revision], hb_version_micro)])
+m4_define([hb_libtool_age],
+	  m4_eval(hb_version_int - hb_libtool_revision))
+m4_define([hb_libtool_current],
+	  m4_eval(hb_version_major + hb_libtool_age))
+HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age
+AC_SUBST(HB_LIBTOOL_VERSION_INFO)
+
+dnl GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
+
+# Functions and headers
+AC_CHECK_FUNCS(mprotect sysconf getpagesize mmap _setmode)
+AC_CHECK_HEADERS(unistd.h sys/mman.h io.h)
+
+# Compiler flags
+AC_CANONICAL_HOST
 if test "x$GCC" = "xyes"; then
+
+	# Make symbols link locally
+	LDFLAGS="$LDFLAGS -Bsymbolic-functions"
+
+	# Make sure we don't link to libstdc++
 	CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
+
+	case "$host" in
+		arm-*-*)
+			# Request byte alignment on arm
+			CXXFLAGS="$CXXFLAGS -mstructure-size-boundary=8"
+		;;
+	esac
 fi
 
 dnl ==========================================================================
 
-PKG_CHECK_MODULES(GLIB, glib-2.0, have_glib=true, have_glib=false)
+PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, have_glib=true, have_glib=false)
 if $have_glib; then
 	AC_DEFINE(HAVE_GLIB, 1, [Have glib2 library])
 fi
 AM_CONDITIONAL(HAVE_GLIB, $have_glib)
 
-PKG_CHECK_MODULES(ICU, icu, have_icu=true, have_icu=false)
+PKG_CHECK_MODULES(GTHREAD, gthread-2.0, have_gthread=true, have_gthread=false)
+if $have_gthread; then
+	AC_DEFINE(HAVE_GTHREAD, 1, [Have gthread2 library])
+fi
+AM_CONDITIONAL(HAVE_GTHREAD, $have_gthread)
+
+PKG_CHECK_MODULES(GOBJECT, gobject-2.0 glib-2.0 >= 2.16, have_gobject=true, have_gobject=false)
+if $have_gobject; then
+	AC_DEFINE(HAVE_GOBJECT, 1, [Have gobject2 library])
+	GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+	AC_SUBST(GLIB_MKENUMS)
+fi
+AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject)
+
+dnl ==========================================================================
+
+PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, have_cairo=false)
+if $have_cairo; then
+	AC_DEFINE(HAVE_CAIRO, 1, [Have cairo graphics library])
+fi
+AM_CONDITIONAL(HAVE_CAIRO, $have_cairo)
+
+PKG_CHECK_MODULES(CAIRO_FT, cairo-ft, have_cairo_ft=true, have_cairo_ft=false)
+if $have_cairo_ft; then
+	AC_DEFINE(HAVE_CAIRO_FT, 1, [Have cairo-ft support in cairo graphics library])
+fi
+AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft)
+
+dnl ==========================================================================
+
+PKG_CHECK_MODULES(ICU, icu, have_icu=true, [
+	have_icu=true
+	AC_CHECK_HEADERS(unicode/uchar.h,, have_icu=false)
+	AC_MSG_CHECKING([for libicuuc])
+	LIBS_old=$LIBS
+	LIBS="$LIBS -licuuc"
+	AC_TRY_LINK([#include <unicode/uchar.h>],
+		    [u_getIntPropertyValue (0, (UProperty)0);],
+		    AC_MSG_RESULT(yes),
+		    AC_MSG_RESULT(no);have_icu=false)
+	LIBS=$LIBS_old
+	if $have_icu; then
+		ICU_CFLAGS=-D_REENTRANT
+		ICU_LIBS="-licuuc"
+		AC_SUBST(ICU_CFLAGS)
+		AC_SUBST(ICU_LIBS)
+	fi
+])
 if $have_icu; then
 	AC_DEFINE(HAVE_ICU, 1, [Have ICU library])
 fi
 AM_CONDITIONAL(HAVE_ICU, $have_icu)
 
-PKG_CHECK_MODULES(GRAPHITE, silgraphite, have_graphite=true, have_graphite=false)
+dnl ==========================================================================
+
+PKG_CHECK_MODULES(GRAPHITE, graphite2, have_graphite=true, have_graphite=false)
 if $have_graphite; then
     AC_DEFINE(HAVE_GRAPHITE, 1, [Have Graphite library])
 fi
 AM_CONDITIONAL(HAVE_GRAPHITE, $have_graphite)
 
-PKG_CHECK_MODULES(FREETYPE, freetype2, have_freetype=true, have_freetype=false)
+dnl ==========================================================================
+
+PKG_CHECK_MODULES(FREETYPE, freetype2 >= 2.3.8, have_freetype=true, have_freetype=false)
 if $have_freetype; then
 	AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
 	_save_libs="$LIBS"
 	_save_cflags="$CFLAGS"
 	LIBS="$LIBS $FREETYPE_LIBS"
 	CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
 	AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
 	LIBS="$_save_libs"
 	CFLAGS="$_save_cflags"
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
 
-dnl ==========================================================================
+dnl ===========================================================================
+
+have_ot=true;
+if $have_ot; then
+	AC_DEFINE(HAVE_OT, 1, [Have native OpenType Layout backend])
+fi
+AM_CONDITIONAL(HAVE_OT, $have_ot)
+
+dnl ===========================================================================
+
+AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true, have_uniscribe=false)
+if $have_uniscribe; then
+	UNISCRIBE_CFLAGS=
+	UNISCRIBE_LIBS="-lusp10 -lgdi32"
+	AC_SUBST(UNISCRIBE_CFLAGS)
+	AC_SUBST(UNISCRIBE_LIBS)
+	AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe backend])
+fi
+AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)
 
 AC_CONFIG_FILES([
+Makefile
 harfbuzz.pc
-Makefile
 src/Makefile
+src/hb-version.h
+util/Makefile
+test/Makefile
 ])
 
 AC_OUTPUT
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -1,147 +1,187 @@
 # Process this file with automake to produce Makefile.in
 
 NULL =
-EXTRA_DIST = 
+BUILT_SOURCES =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+MAINTAINERCLEANFILES =
 
 # The following warning options are useful for debugging: -Wpadded -Wcast-align
 #AM_CXXFLAGS =
 
 lib_LTLIBRARIES = libharfbuzz.la
 
 HBCFLAGS =
 HBLIBS =
 HBSOURCES =  \
-	hb-blob.c \
-	hb-blob-private.h \
-	hb-buffer.cc \
+	hb-blob.cc \
 	hb-buffer-private.hh \
-	hb-common.c \
+	hb-buffer.cc \
+	hb-common.cc \
+	hb-fallback-shape-private.hh \
+	hb-fallback-shape.cc \
+	hb-font-private.hh \
 	hb-font.cc \
-	hb-font-private.h \
-	hb-object-private.h \
+	hb-mutex-private.hh \
+	hb-object-private.hh \
 	hb-open-file-private.hh \
 	hb-open-type-private.hh \
-	hb-language.c \
-	hb-ot-head-private.hh \
-	hb-private.h \
+	hb-ot-head-table.hh \
+	hb-ot-hhea-table.hh \
+	hb-ot-hmtx-table.hh \
+	hb-ot-maxp-table.hh \
+	hb-ot-name-table.hh \
+	hb-ot-tag.cc \
+	hb-private.hh \
 	hb-shape.cc \
-	hb-unicode.c \
-	hb-unicode-private.h \
+	hb-tt-font.cc \
+	hb-unicode-private.hh \
+	hb-unicode.cc \
 	$(NULL)
 HBHEADERS = \
 	hb.h \
 	hb-blob.h \
 	hb-buffer.h \
 	hb-common.h \
 	hb-font.h \
-	hb-language.h \
 	hb-shape.h \
 	hb-unicode.h \
+	hb-version.h \
 	$(NULL)
 
+if HAVE_OT
 HBSOURCES += \
 	hb-ot-layout.cc \
 	hb-ot-layout-common-private.hh \
-	hb-ot-layout-gdef-private.hh \
-	hb-ot-layout-gpos-private.hh \
+	hb-ot-layout-gdef-table.hh \
+	hb-ot-layout-gpos-table.hh \
 	hb-ot-layout-gsubgpos-private.hh \
-	hb-ot-layout-gsub-private.hh \
+	hb-ot-layout-gsub-table.hh \
 	hb-ot-layout-private.hh \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
 	hb-ot-shape.cc \
 	hb-ot-shape-complex-arabic.cc \
-	hb-ot-shape-complex-arabic-table.h \
+	hb-ot-shape-complex-arabic-table.hh \
+	hb-ot-shape-complex-indic.cc \
+	hb-ot-shape-complex-indic-machine.hh \
+	hb-ot-shape-complex-indic-table.hh \
+	hb-ot-shape-complex-misc.cc \
 	hb-ot-shape-complex-private.hh \
+	hb-ot-shape-normalize.cc \
 	hb-ot-shape-private.hh \
-	hb-ot-tag.c \
 	$(NULL)
 HBHEADERS += \
 	hb-ot.h \
 	hb-ot-layout.h \
 	hb-ot-shape.h \
 	hb-ot-tag.h \
 	$(NULL)
+endif
 
 if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
-HBSOURCES += \
-	hb-glib.c \
-	$(NULL)
-HBHEADERS += \
-	hb-glib.h \
-	$(NULL)
+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.c \
-	$(NULL)
-HBHEADERS += \
-	hb-icu.h \
-	$(NULL)
+HBSOURCES += hb-icu.cc
+HBHEADERS += hb-icu.h
 endif
 
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
-HBSOURCES += \
-	hb-ft.c \
-	$(NULL)
-HBHEADERS += \
-	hb-ft.h \
-	$(NULL)
+HBSOURCES += hb-ft.cc
+HBHEADERS += hb-ft.h
 endif
 
 if HAVE_GRAPHITE
 HBCFLAGS += $(GRAPHITE_CFLAGS)
 HBLIBS   += $(GRAPHITE_LIBS)
-HBSOURCES += \
-	hb-graphite.cc \
-	$(NULL)
-HBHEADERS += \
-	hb-graphite.h \
-	$(NULL)
+HBSOURCES += hb-graphite2.cc
+HBHEADERS += hb-graphite2.h
+endif
+
+if HAVE_UNISCRIBE
+HBCFLAGS += $(UNISCRIBE_CFLAGS)
+HBLIBS   += $(UNISCRIBE_LIBS)
+HBSOURCES += hb-uniscribe.cc
+HBHEADERS += hb-uniscribe.h
 endif
 
 CXXLINK = $(LINK)
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
+nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
+libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
 libharfbuzz_la_LIBADD = $(HBLIBS)
 pkginclude_HEADERS = $(HBHEADERS)
+nodist_pkginclude_HEADERS = hb-version.h
 
 
 GENERATORS = \
-	gen-arabic-joining-table.py \
+	gen-arabic-table.py \
+	gen-indic-table.py \
 	$(NULL)
 
 EXTRA_DIST += $(GENERATORS)
 
-noinst_PROGRAMS = main test
+BUILT_SOURCES += hb-ot-shape-complex-indic-machine.hh
+EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
+hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
+	$(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
+	mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
+
+noinst_PROGRAMS = main
+bin_PROGRAMS =
 
 main_SOURCES = main.cc
 main_CPPFLAGS = $(HBCFLAGS)
 main_LDADD = libharfbuzz.la $(HBLIBS)
 
-test_SOURCES = test.c
-test_CPPFLAGS = $(HBCFLAGS)
-test_LDADD = libharfbuzz.la $(HBLIBS)
-
-TESTS = \
+dist_check_SCRIPTS = \
 	check-c-linkage-decls.sh \
 	check-header-guards.sh \
 	check-internal-symbols.sh \
+	check-includes.sh \
 	$(NULL)
 
 if HAVE_ICU
 else
-if HAVE_GRAPHITE
-else
-TESTS += check-libstdc++.sh
-endif
+dist_check_SCRIPTS += check-libstdc++.sh
 endif
 
+TESTS = $(dist_check_SCRIPTS)
+TESTS_ENVIRONMENT = \
+	srcdir="$(srcdir)" \
+	MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
+	HBSOURCES="$(HBSOURCES)" \
+	HBHEADERS="$(HBHEADERS)" \
+	$(NULL)
+
+scan:
+	g-ir-scanner $(HBCFLAGS) $(HBHEADERS) -n hb --strip-prefix=hb --library libharfbuzz.la
+
+
 -include $(top_srcdir)/git.mk
--- a/gfx/harfbuzz/src/Makefile.in
+++ b/gfx/harfbuzz/src/Makefile.in
@@ -31,50 +31,56 @@ srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE         = harfbuzz
 LIBRARY_NAME   = mozharfbuzz
 LIBXUL_LIBRARY = 1
 
-CSRCS =            \
-  hb-blob.c        \
-  hb-language.c    \
-  hb-ot-tag.c      \
-  hb-unicode.c     \
-  $(NULL)
-
-CPPSRCS	=          \
-  hb-buffer.cc     \
-  hb-font.cc       \
-  hb-ot-layout.cc  \
-  hb-ot-map.cc     \
-  hb-ot-shape-complex-arabic.cc \
-  hb-ot-shape.cc   \
-  hb-shape.cc      \
+CPPSRCS	=                        \
+  hb-blob.cc                     \
+  hb-buffer.cc                   \
+  hb-common.cc                   \
+  hb-fallback-shape.cc           \
+  hb-font.cc                     \
+  hb-ot-layout.cc                \
+  hb-ot-map.cc                   \
+  hb-ot-shape-complex-arabic.cc  \
+  hb-ot-shape-complex-indic.cc   \
+  hb-ot-shape-complex-misc.cc    \
+  hb-ot-shape-normalize.cc       \
+  hb-ot-shape.cc                 \
+  hb-ot-tag.cc                   \
+  hb-shape.cc                    \
+  hb-unicode.cc                  \
   $(NULL)
 
 EXPORTS_NAMESPACES = harfbuzz
 
 EXPORTS_harfbuzz = \
   hb.h             \
   hb-blob.h        \
   hb-buffer.h      \
   hb-common.h      \
   hb-font.h        \
-  hb-language.h    \
   hb-ot.h          \
   hb-ot-layout.h   \
   hb-ot-tag.h      \
   hb-ot-shape.h    \
   hb-shape.h       \
   hb-unicode.h     \
+  hb-version.h     \
   $(NULL)
 
 LOCAL_INCLUDES  += -I$(srcdir) 
 
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DPACKAGE_VERSION="\"moz\""
 DEFINES += -DPACKAGE_BUGREPORT="\"http://bugzilla.mozilla.org/\""
+DEFINES += -DHAVE_OT=1
+
+# Cancel the effect of the -DDEBUG macro if present,
+# because harfbuzz uses that name for its own purposes
+COMPILE_CXXFLAGS += -UDEBUG
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/check-c-linkage-decls.sh
@@ -0,0 +1,20 @@
+#!/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'`
+
+
+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 HB_BEGIN_DECLS / HB_END_DECLS"
+		stat=1
+	fi
+done
+
+exit $stat
old mode 100644
new mode 100755
--- a/gfx/harfbuzz/src/check-header-guards.sh
+++ b/gfx/harfbuzz/src/check-header-guards.sh
@@ -1,20 +1,25 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
 test -z "$srcdir" && srcdir=.
 stat=0
 
-cd "$srcdir"
+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'`
+
 
-for x in hb-*.h hb-*.hh ; do
-	tag=`echo "$x" | tr 'a-z.-' 'A-Z_'`
-	lines=`grep "\<$tag\>" "$x" | wc -l`
+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'`
 	if test "x$lines" != x3; then
 		echo "Ouch, header file $x does not have correct preprocessor guards"
 		stat=1
 	fi
 done
 
 exit $stat
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/check-includes.sh
@@ -0,0 +1,42 @@
+#!/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"
+
+
+echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
+
+for x in $HBHEADERS; do
+	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
+	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
+
+
+exit $stat
old mode 100644
new mode 100755
--- a/gfx/harfbuzz/src/check-internal-symbols.sh
+++ b/gfx/harfbuzz/src/check-internal-symbols.sh
@@ -1,28 +1,34 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
 if which nm 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-internal-symbols.sh: 'nm' not found; skipping test"
-	exit 0
+	exit 77
 fi
 
-test -z "$srcdir" && srcdir=.
-test -z "$MAKE" && MAKE=make
-stat=0
-
-so=.libs/libharfbuzz.so
-if test -f "$so"; then
-	echo "Checking that we are exposing internal symbols"
-	if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
-		echo "Ouch, internal symbols exposed"
-		stat=1
+tested=false
+for suffix in so; do
+	so=.libs/libharfbuzz.$suffix
+	if test -f "$so"; then
+		echo "Checking that we are exposing internal symbols"
+		if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
+			echo "Ouch, internal symbols exposed"
+			stat=1
+		fi
+		tested=true
 	fi
-else
-	echo "check-internal-symbols.sh: libharfbuzz.so not found; skipping test"
+done
+if ! $tested; then
+	echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
+	exit 77
 fi
 
 exit $stat
--- a/gfx/harfbuzz/src/check-libstdc++.sh
+++ b/gfx/harfbuzz/src/check-libstdc++.sh
@@ -1,27 +1,34 @@
 #!/bin/sh
 
 LC_ALL=C
 export LC_ALL
 
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
 if which ldd 2>/dev/null >/dev/null; then
 	:
 else
 	echo "check-libstdc++.sh: 'ldd' not found; skipping test"
-	exit 0
+	exit 77
 fi
 
-test -z "$srcdir" && srcdir=.
-stat=0
-
-so=.libs/libharfbuzz.so
-if test -f "$so"; then
-	echo "Checking that we are not linking to libstdc++"
-	if ldd $so | grep 'libstdc[+][+]'; then
-		echo "Ouch, linked to libstdc++"
-		stat=1
+tested=false
+for suffix in so dylib; do
+	so=.libs/libharfbuzz.$suffix
+	if test -f "$so"; then
+		echo "Checking that we are not linking to libstdc++"
+		if ldd $so | grep 'libstdc[+][+]'; then
+			echo "Ouch, linked to libstdc++"
+			stat=1
+		fi
+		tested=true
 	fi
-else
-	echo "check-libstdc++.sh: libharfbuzz.so not found; skipping test"
+done
+if ! $tested; then
+	echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
+	exit 77
 fi
 
 exit $stat
deleted file mode 100644
--- a/gfx/harfbuzz/src/gen-arabic-joining-table.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python
-
-import sys
-
-header = sys.stdin.readline(), sys.stdin.readline()
-dic = dict()
-for line in sys.stdin:
-	if line[:1] != '0':
-		continue
-
-	fields = [x.strip() for x in line.split(';')]
-	u = int(fields[0], 16)
-
-	if u == 0x200C or u == 0x200D:
-		continue
-	if u < 0x0600:
-		raise Exception ("Ooops, unexpected unicode character: ", fields)
-	dic[u] = fields
-
-v = dic.keys()
-v.sort()
-min_u, max_u = v[0], v[-1]
-occupancy = len(v) * 100 / (max_u - min_u + 1)
-
-# Maintain at least 40% occupancy in the table */
-if occupancy < 40:
-	raise Exception ("Table too sparse, please investigate: ", occupancy)
-
-print "/* == Start of generated table == */"
-print "/*"
-print " * The following table is generated by running:"
-print " *"
-print " *   ./gen-arabic-joining-table.py < ArabicShaping.txt"
-print " *"
-print " * on the ArabicShaping.txt file with the header:"
-print " *"
-for line in header:
-	print " * %s" % (line.strip())
-print " */"
-
-print "#define JOINING_TABLE_FIRST	0x%04x" % min_u
-print "#define JOINING_TABLE_LAST	0x%04x" % max_u
-print "static const uint8_t joining_table[JOINING_TABLE_LAST-JOINING_TABLE_FIRST+2] ="
-print "{"
-
-for i in range(min_u, max_u + 1):
-	if i not in dic:
-		print "  JOINING_TYPE_X, /* %04X */" % i
-	else:
-		entry = dic[i]
-		if entry[3] in ["ALAPH", "DALATH RISH"]:
-			value = "JOINING_GROUP_" + entry[3].replace(' ', '_')
-		else:
-			value = "JOINING_TYPE_" + entry[2]
-		print "  %s, /* %s */" % (value, '; '.join(entry))
-print "  JOINING_TYPE_X  /* dummy */"
-print "};"
-print "/* == End of generated table == */"
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/gen-arabic-table.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+
+import sys
+
+if len (sys.argv) < 2:
+	print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt"
+	sys.exit (1)
+
+f = file (sys.argv[1])
+
+header = f.readline (), f.readline ()
+while f.readline ().find ('##################') < 0:
+	pass
+
+
+print "/* == Start of generated table == */"
+print "/*"
+print " * The following table is generated by running:"
+print " *"
+print " *   ./gen-arabic-table.py ArabicShaping.txt"
+print " *"
+print " * on files with these headers:"
+print " *"
+for line in header:
+	print " * %s" % (line.strip())
+print " */"
+
+print "static const uint8_t joining_table[] ="
+print "{"
+
+
+min_u = 0x110000
+max_u = 0
+num = 0
+last = -1
+block = ''
+for line in f:
+
+	if line[0] == '#':
+		if line.find (" characters"):
+			block = line[2:].strip ()
+		continue
+
+	fields = [x.strip () for x in line.split (';')]
+	if len (fields) == 1:
+		continue
+
+	u = int (fields[0], 16)
+	if u == 0x200C or u == 0x200D:
+		continue
+	if u < last:
+		raise Exception ("Input data character not sorted", u)
+	min_u = min (min_u, u)
+	max_u = max (max_u, u)
+	num += 1
+
+	if block:
+		print "\n  /* %s */\n" % block
+		block = ''
+
+	if last != -1:
+		last += 1
+		while last < u:
+			print "  JOINING_TYPE_X, /* %04X */" % last
+			last += 1
+	else:
+		last = u
+
+	if fields[3] in ["ALAPH", "DALATH RISH"]:
+		value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
+	else:
+		value = "JOINING_TYPE_" + fields[2]
+	print "  %s, /* %s */" % (value, '; '.join(fields))
+
+print
+print "};"
+print
+
+print "#define JOINING_TABLE_FIRST	0x%04X" % min_u
+print "#define JOINING_TABLE_LAST	0x%04X" % max_u
+print
+
+print "/* == End of generated table == */"
+
+occupancy = num * 100 / (max_u - min_u + 1)
+# Maintain at least 40% occupancy in the table */
+if occupancy < 40:
+	raise Exception ("Table too sparse, please investigate: ", occupancy)
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/gen-indic-table.py
@@ -0,0 +1,208 @@
+#!/usr/bin/python
+
+import sys
+
+if len (sys.argv) < 4:
+	print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt"
+	sys.exit (1)
+
+files = [file (sys.argv[i+1]) for i in range (3)]
+
+headers = [[f.readline () for i in range (2)] for f in files]
+
+blocks = {}
+data = [{} for f in files]
+values = [{} for f in files]
+for i, f in enumerate (files):
+	for line in f:
+
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+
+		uu = fields[0].split ('..')
+		start = int (uu[0], 16)
+		if len (uu) == 1:
+			end = start
+		else:
+			end = int (uu[1], 16)
+
+		t = fields[1]
+
+		for u in range (start, end + 1):
+			data[i][u] = t
+		values[i][t] = values[i].get (t, 0) + 1
+
+		if i == 2:
+			blocks[t] = (start, end)
+
+# Merge data into one dict:
+defaults = ('Other', 'Not_Applicable', 'No_Block')
+for i,v in enumerate (defaults):
+	values[i][v] = values[i].get (v, 0) + 1
+combined = {}
+for i,d in enumerate (data):
+	for u,v in d.items ():
+		if i == 2 and not u in combined:
+			continue
+		if not u in combined:
+			combined[u] = list (defaults)
+		combined[u][i] = v
+data = combined
+del combined
+num = len (data)
+
+# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
+singles = {}
+for u in [0x00A0, 0x25CC]:
+	singles[u] = data[u]
+	del data[u]
+
+print "/* == Start of generated table == */"
+print "/*"
+print " * The following table is generated by running:"
+print " *"
+print " *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt"
+print " *"
+print " * on files with these headers:"
+print " *"
+for h in headers:
+	for l in h:
+		print " * %s" % (l.strip())
+print " */"
+
+# Shorten values
+print
+short = [{
+	"Bindu":		'Bi',
+	"Visarga":		'Vs',
+	"Vowel":		'Vo',
+	"Vowel_Dependent":	'M',
+	"Other":		'x',
+},{
+	"Not_Applicable":	'x',
+}]
+all_shorts = [[],[]]
+
+# Add some of the values, to make them more readable, and to avoid duplicates
+
+
+for i in range (2):
+	for v,s in short[i].items ():
+		all_shorts[i].append (s)
+
+what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
+what_short = ["ISC", "IMC"]
+for i in range (2):
+	print
+	vv = values[i].keys ()
+	vv.sort ()
+	for v in vv:
+		v_no_and = v.replace ('_And_', '_')
+		if v in short[i]:
+			s = short[i][v]
+		else:
+			s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')])
+			if s in all_shorts[i]:
+				raise Exception ("Duplicate short value alias", v, s)
+			all_shorts[i].append (s)
+			short[i][v] = s
+		print "#define %s_%s	%s_%s	%s/* %3d chars; %s */" % \
+			(what_short[i], s, what[i], v.upper (), \
+			'	'* ((48-1 - len (what[i]) - 1 - len (v)) / 8), \
+			values[i][v], v)
+print
+print "#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)"
+print
+print
+
+def print_block (block, start, end, data):
+	print
+	print
+	print "  /* %s  (%04X..%04X) */" % (block, start, end)
+	num = 0
+	for u in range (start, end+1):
+		if u % 8 == 0:
+			print
+			print "  /* %04X */" % u,
+		if u in data:
+			num += 1
+		d = data.get (u, defaults)
+		sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])))
+
+	if num == 0:
+		# Filler block, don't check occupancy
+		return
+	total = end - start + 1
+	occupancy = num * 100. / total
+	# Maintain at least 30% occupancy in the table */
+	if occupancy < 30:
+		raise Exception ("Table too sparse, please investigate: ", occupancy, block)
+
+uu = data.keys ()
+uu.sort ()
+
+last = -1
+num = 0
+offset = 0
+starts = []
+ends = []
+print "static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {"
+for u in uu:
+	if u <= last:
+		continue
+	block = data[u][2]
+	(start, end) = blocks[block]
+
+	if start != last + 1:
+		if start - last <= 33:
+			print_block ("FILLER", last+1, start-1, data)
+			last = start-1
+		else:
+			if last >= 0:
+				ends.append (last + 1)
+				offset += ends[-1] - starts[-1]
+			print
+			print
+			print "#define indic_offset_0x%04x %d" % (start, offset)
+			starts.append (start)
+
+	print_block (block, start, end, data)
+	last = end
+ends.append (last + 1)
+offset += ends[-1] - starts[-1]
+print
+print
+print "#define indic_offset_total %d" % offset
+print
+print "};"
+
+print
+print "static INDIC_TABLE_ELEMENT_TYPE"
+print "get_indic_categories (hb_codepoint_t u)"
+print "{"
+for (start,end) in zip (starts, ends):
+	offset = "indic_offset_0x%04x" % start
+	print "  if (0x%04X <= u && u <= 0x%04X) return indic_table[u - 0x%04X + %s];" % (start, end, start, offset)
+for u,d in singles.items ():
+	print "  if (unlikely (u == 0x%04X)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+print "  return _(x,x);"
+print "}"
+
+print
+print "#undef _"
+for i in range (2):
+	print
+	vv = values[i].keys ()
+	vv.sort ()
+	for v in vv:
+		print "#undef %s_%s" % \
+			(what_short[i], short[i][v])
+
+print
+print
+print "/* == End of generated table == */"
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-blob-private.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * 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_BLOB_PRIVATE_H
-#define HB_BLOB_PRIVATE_H
-
-#include "hb-private.h"
-
-#include "hb-blob.h"
-
-HB_BEGIN_DECLS
-
-
-struct _hb_blob_t {
-  hb_reference_count_t ref_count;
-
-  unsigned int length;
-
-  hb_mutex_t lock;
-  /* the rest are protected by lock */
-
-  unsigned int lock_count;
-  hb_memory_mode_t mode;
-
-  const char *data;
-
-  hb_destroy_func_t destroy;
-  void *user_data;
-};
-
-extern HB_INTERNAL hb_blob_t _hb_blob_nil;
-
-
-HB_END_DECLS
-
-#endif /* HB_BLOB_PRIVATE_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-blob.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-blob-private.h"
-
-#ifdef HAVE_SYS_MMAN_H
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <sys/mman.h>
-#endif /* HAVE_SYS_MMAN_H */
-
-#include <stdio.h>
-#include <errno.h>
-
-HB_BEGIN_DECLS
-
-
-#ifndef HB_DEBUG_BLOB
-#define HB_DEBUG_BLOB (HB_DEBUG+0)
-#endif
-
-hb_blob_t _hb_blob_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-
-  0, /* length */
-
-  HB_MUTEX_INIT, /* lock */
-
-  0, /* lock_count */
-  HB_MEMORY_MODE_READONLY, /* mode */
-
-  NULL, /* data */
-
-  NULL, /* destroy */
-  NULL /* user_data */
-};
-
-static void
-_hb_blob_destroy_user_data (hb_blob_t *blob)
-{
-  if (blob->destroy) {
-    blob->destroy (blob->user_data);
-    blob->destroy = NULL;
-    blob->user_data = NULL;
-  }
-}
-
-static void
-_hb_blob_unlock_and_destroy (hb_blob_t *blob)
-{
-  hb_blob_unlock (blob);
-  hb_blob_destroy (blob);
-}
-
-hb_blob_t *
-hb_blob_create (const char        *data,
-		unsigned int       length,
-		hb_memory_mode_t   mode,
-		hb_destroy_func_t  destroy,
-		void              *user_data)
-{
-  hb_blob_t *blob;
-
-  if (!length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob)) {
-    if (destroy)
-      destroy (user_data);
-    return &_hb_blob_nil;
-  }
-
-  hb_mutex_init (blob->lock);
-  blob->lock_count = 0;
-
-  blob->data = data;
-  blob->length = length;
-  blob->mode = mode;
-
-  blob->destroy = destroy;
-  blob->user_data = user_data;
-
-  if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
-    blob->mode = HB_MEMORY_MODE_READONLY;
-    if (!hb_blob_try_writable (blob)) {
-      hb_blob_destroy (blob);
-      return &_hb_blob_nil;
-    }
-  }
-
-  return blob;
-}
-
-hb_blob_t *
-hb_blob_create_sub_blob (hb_blob_t    *parent,
-			 unsigned int  offset,
-			 unsigned int  length)
-{
-  hb_blob_t *blob;
-  const char *pdata;
-
-  if (!length || offset >= parent->length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob))
-    return &_hb_blob_nil;
-
-  pdata = hb_blob_lock (parent);
-
-  blob->data = pdata + offset;
-  blob->length = MIN (length, parent->length - offset);
-
-  hb_mutex_lock (parent->lock);
-  blob->mode = parent->mode;
-  hb_mutex_unlock (parent->lock);
-
-  blob->destroy = (hb_destroy_func_t) _hb_blob_unlock_and_destroy;
-  blob->user_data = hb_blob_reference (parent);
-
-  return blob;
-}
-
-hb_blob_t *
-hb_blob_create_empty (void)
-{
-  return &_hb_blob_nil;
-}
-
-hb_blob_t *
-hb_blob_reference (hb_blob_t *blob)
-{
-  HB_OBJECT_DO_REFERENCE (blob);
-}
-
-unsigned int
-hb_blob_get_reference_count (hb_blob_t *blob)
-{
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (blob);
-}
-
-void
-hb_blob_destroy (hb_blob_t *blob)
-{
-  HB_OBJECT_DO_DESTROY (blob);
-
-  _hb_blob_destroy_user_data (blob);
-
-  free (blob);
-}
-
-unsigned int
-hb_blob_get_length (hb_blob_t *blob)
-{
-  return blob->length;
-}
-
-const char *
-hb_blob_lock (hb_blob_t *blob)
-{
-  if (HB_OBJECT_IS_INERT (blob))
-    return NULL;
-
-  hb_mutex_lock (blob->lock);
-
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	     blob->lock_count, blob->data));
-
-  blob->lock_count++;
-
-  hb_mutex_unlock (blob->lock);
-
-  return blob->data;
-}
-
-void
-hb_blob_unlock (hb_blob_t *blob)
-{
-  if (HB_OBJECT_IS_INERT (blob))
-    return;
-
-  hb_mutex_lock (blob->lock);
-
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	     blob->lock_count, blob->data));
-
-  assert (blob->lock_count > 0);
-  blob->lock_count--;
-
-  hb_mutex_unlock (blob->lock);
-}
-
-hb_bool_t
-hb_blob_is_writable (hb_blob_t *blob)
-{
-  hb_memory_mode_t mode;
-
-  if (HB_OBJECT_IS_INERT (blob))
-    return FALSE;
-
-  hb_mutex_lock (blob->lock);
-
-  mode = blob->mode;
-
-  hb_mutex_unlock (blob->lock);
-
-  return mode == HB_MEMORY_MODE_WRITABLE;
-}
-
-
-static hb_bool_t
-_try_make_writable_inplace_unix_locked (hb_blob_t *blob)
-{
-#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
-  uintptr_t pagesize = -1, mask, length;
-  const char *addr;
-
-#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
-  pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
-#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
-  pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
-#elif defined(HAVE_GETPAGESIZE)
-  pagesize = (uintptr_t) getpagesize ();
-#endif
-
-  if ((uintptr_t) -1L == pagesize) {
-    (void) (HB_DEBUG_BLOB &&
-      fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno)));
-    return FALSE;
-  }
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s: pagesize is %lu\n", blob, __FUNCTION__, (unsigned long) pagesize));
-
-  mask = ~(pagesize-1);
-  addr = (const char *) (((uintptr_t) blob->data) & mask);
-  length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%lu bytes)\n",
-	     blob, __FUNCTION__,
-	     addr, addr+length, (unsigned long) length));
-  if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
-    (void) (HB_DEBUG_BLOB &&
-      fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno)));
-    return FALSE;
-  }
-
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s: successfully made [%p..%p] (%lu bytes) writable\n",
-	     blob, __FUNCTION__,
-	     addr, addr+length, (unsigned long) length));
-  return TRUE;
-#else
-  return FALSE;
-#endif
-}
-
-static void
-try_writable_inplace_locked (hb_blob_t *blob)
-{
-  (void) (HB_DEBUG_BLOB &&
-    fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__));
-
-  if (_try_make_writable_inplace_unix_locked (blob)) {
-    (void) (HB_DEBUG_BLOB &&
-      fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__));
-    blob->mode = HB_MEMORY_MODE_WRITABLE;
-  } else {
-    (void) (HB_DEBUG_BLOB &&
-      fprintf (stderr, "%p %s: making writable -> FAILED\n", blob, __FUNCTION__));
-    /* Failed to make writable inplace, mark that */
-    blob->mode = HB_MEMORY_MODE_READONLY;
-  }
-}
-
-hb_bool_t
-hb_blob_try_writable_inplace (hb_blob_t *blob)
-{
-  hb_memory_mode_t mode;
-
-  if (HB_OBJECT_IS_INERT (blob))
-    return FALSE;
-
-  hb_mutex_lock (blob->lock);
-
-  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
-    try_writable_inplace_locked (blob);
-
-  mode = blob->mode;
-
-  hb_mutex_unlock (blob->lock);
-
-  return mode == HB_MEMORY_MODE_WRITABLE;
-}
-
-hb_bool_t
-hb_blob_try_writable (hb_blob_t *blob)
-{
-  hb_memory_mode_t mode;
-
-  if (HB_OBJECT_IS_INERT (blob))
-    return FALSE;
-
-  hb_mutex_lock (blob->lock);
-
-  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
-    try_writable_inplace_locked (blob);
-
-  if (blob->mode == HB_MEMORY_MODE_READONLY)
-  {
-    char *new_data;
-
-    (void) (HB_DEBUG_BLOB &&
-      fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
-	       blob->lock_count, blob->data));
-
-    if (blob->lock_count)
-      goto done;
-
-    new_data = malloc (blob->length);
-    if (new_data) {
-      (void) (HB_DEBUG_BLOB &&
-	fprintf (stderr, "%p %s: dupped successfully -> %p\n", blob, __FUNCTION__, blob->data));
-      memcpy (new_data, blob->data, blob->length);
-      _hb_blob_destroy_user_data (blob);
-      blob->mode = HB_MEMORY_MODE_WRITABLE;
-      blob->data = new_data;
-      blob->destroy = free;
-      blob->user_data = new_data;
-    }
-  }
-
-done:
-  mode = blob->mode;
-
-  hb_mutex_unlock (blob->lock);
-
-  return mode == HB_MEMORY_MODE_WRITABLE;
-}
-
-
-HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -0,0 +1,324 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-blob.h"
+#include "hb-object-private.hh"
+
+#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#include <sys/mman.h>
+#endif /* HAVE_SYS_MMAN_H */
+
+#include <stdio.h>
+#include <errno.h>
+
+
+
+#ifndef HB_DEBUG_BLOB
+#define HB_DEBUG_BLOB (HB_DEBUG+0)
+#endif
+
+
+struct _hb_blob_t {
+  hb_object_header_t header;
+
+  bool immutable;
+
+  const char *data;
+  unsigned int length;
+  hb_memory_mode_t mode;
+
+  void *user_data;
+  hb_destroy_func_t destroy;
+};
+
+static hb_blob_t _hb_blob_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  TRUE, /* immutable */
+
+  NULL, /* data */
+  0, /* length */
+  HB_MEMORY_MODE_READONLY, /* mode */
+
+  NULL, /* user_data */
+  NULL  /* destroy */
+};
+
+
+static bool _try_writable (hb_blob_t *blob);
+
+static void
+_hb_blob_destroy_user_data (hb_blob_t *blob)
+{
+  if (blob->destroy) {
+    blob->destroy (blob->user_data);
+    blob->user_data = NULL;
+    blob->destroy = NULL;
+  }
+}
+
+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;
+
+  if (!length || !(blob = hb_object_create<hb_blob_t> ())) {
+    if (destroy)
+      destroy (user_data);
+    return &_hb_blob_nil;
+  }
+
+  blob->data = data;
+  blob->length = length;
+  blob->mode = mode;
+
+  blob->user_data = user_data;
+  blob->destroy = destroy;
+
+  if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
+    blob->mode = HB_MEMORY_MODE_READONLY;
+    if (!_try_writable (blob)) {
+      hb_blob_destroy (blob);
+      return &_hb_blob_nil;
+    }
+  }
+
+  return blob;
+}
+
+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)
+    return &_hb_blob_nil;
+
+  hb_blob_make_immutable (parent);
+
+  blob = hb_blob_create (parent->data + offset,
+			 MIN (length, parent->length - offset),
+			 parent->mode,
+			 hb_blob_reference (parent),
+			 (hb_destroy_func_t) hb_blob_destroy);
+
+  return blob;
+}
+
+hb_blob_t *
+hb_blob_get_empty (void)
+{
+  return &_hb_blob_nil;
+}
+
+hb_blob_t *
+hb_blob_reference (hb_blob_t *blob)
+{
+  return hb_object_reference (blob);
+}
+
+void
+hb_blob_destroy (hb_blob_t *blob)
+{
+  if (!hb_object_destroy (blob)) return;
+
+  _hb_blob_destroy_user_data (blob);
+
+  free (blob);
+}
+
+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);
+}
+
+void *
+hb_blob_get_user_data (hb_blob_t          *blob,
+		       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (blob, key);
+}
+
+
+void
+hb_blob_make_immutable (hb_blob_t *blob)
+{
+  if (hb_object_is_inert (blob))
+    return;
+
+  blob->immutable = TRUE;
+}
+
+hb_bool_t
+hb_blob_is_immutable (hb_blob_t *blob)
+{
+  return blob->immutable;
+}
+
+
+unsigned int
+hb_blob_get_length (hb_blob_t *blob)
+{
+  return blob->length;
+}
+
+const char *
+hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
+{
+  if (length)
+    *length = blob->length;
+
+  return blob->data;
+}
+
+char *
+hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
+{
+  if (!_try_writable (blob)) {
+    if (length)
+      *length = 0;
+
+    return NULL;
+  }
+
+  if (length)
+    *length = blob->length;
+
+  return const_cast<char *> (blob->data);
+}
+
+
+static hb_bool_t
+_try_make_writable_inplace_unix (hb_blob_t *blob)
+{
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
+  uintptr_t pagesize = -1, mask, length;
+  const char *addr;
+
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+  pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
+#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+  pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
+#elif defined(HAVE_GETPAGESIZE)
+  pagesize = (uintptr_t) getpagesize ();
+#endif
+
+  if ((uintptr_t) -1L == pagesize) {
+    DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
+    return FALSE;
+  }
+  DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
+
+  mask = ~(pagesize-1);
+  addr = (const char *) (((uintptr_t) blob->data) & mask);
+  length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
+  DEBUG_MSG_FUNC (BLOB, blob,
+		  "calling mprotect on [%p..%p] (%lu bytes)",
+		  addr, addr+length, (unsigned long) length);
+  if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
+    DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
+    return FALSE;
+  }
+
+  blob->mode = HB_MEMORY_MODE_WRITABLE;
+
+  DEBUG_MSG_FUNC (BLOB, blob,
+		  "successfully made [%p..%p] (%lu bytes) writable\n",
+		  addr, addr+length, (unsigned long) length);
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+static bool
+_try_writable_inplace (hb_blob_t *blob)
+{
+  DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
+
+  if (_try_make_writable_inplace_unix (blob))
+    return TRUE;
+
+  DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
+
+  /* Failed to make writable inplace, mark that */
+  blob->mode = HB_MEMORY_MODE_READONLY;
+  return FALSE;
+}
+
+static bool
+_try_writable (hb_blob_t *blob)
+{
+  if (blob->immutable)
+    return FALSE;
+
+  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+    return TRUE;
+
+  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
+    return TRUE;
+
+  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+    return TRUE;
+
+
+  DEBUG_MSG_FUNC (BLOB, blob, "currect data is -> %p\n", blob->data);
+
+  char *new_data;
+
+  new_data = (char *) malloc (blob->length);
+  if (unlikely (!new_data))
+    return FALSE;
+
+  DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
+
+  memcpy (new_data, blob->data, blob->length);
+  _hb_blob_destroy_user_data (blob);
+  blob->mode = HB_MEMORY_MODE_WRITABLE;
+  blob->data = new_data;
+  blob->user_data = new_data;
+  blob->destroy = free;
+
+  return TRUE;
+}
+
+
--- a/gfx/harfbuzz/src/hb-blob.h
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -40,50 +40,58 @@ typedef enum {
 } hb_memory_mode_t;
 
 typedef struct _hb_blob_t hb_blob_t;
 
 hb_blob_t *
 hb_blob_create (const char        *data,
 		unsigned int       length,
 		hb_memory_mode_t   mode,
-		hb_destroy_func_t  destroy,
-		void              *user_data);
+		void              *user_data,
+		hb_destroy_func_t  destroy);
 
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
 			 unsigned int  offset,
 			 unsigned int  length);
 
 hb_blob_t *
-hb_blob_create_empty (void);
+hb_blob_get_empty (void);
 
 hb_blob_t *
 hb_blob_reference (hb_blob_t *blob);
 
-unsigned int
-hb_blob_get_reference_count (hb_blob_t *blob);
+void
+hb_blob_destroy (hb_blob_t *blob);
+
+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);
+
+
+void *
+hb_blob_get_user_data (hb_blob_t          *blob,
+		       hb_user_data_key_t *key);
+
 
 void
-hb_blob_destroy (hb_blob_t *blob);
+hb_blob_make_immutable (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_is_immutable (hb_blob_t *blob);
+
 
 unsigned int
 hb_blob_get_length (hb_blob_t *blob);
 
 const char *
-hb_blob_lock (hb_blob_t *blob);
-
-void
-hb_blob_unlock (hb_blob_t *blob);
+hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
 
-hb_bool_t
-hb_blob_is_writable (hb_blob_t *blob);
-
-hb_bool_t
-hb_blob_try_writable_inplace (hb_blob_t *blob);
-
-hb_bool_t
-hb_blob_try_writable (hb_blob_t *blob);
+char *
+hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
 
 
 HB_END_DECLS
 
 #endif /* HB_BLOB_H */
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -1,13 +1,14 @@
 /*
- * Copyright (C) 1998-2004  David Turner and Werner Lemberg
- * Copyright (C) 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 2011  Google, Inc.
  *
- * This is part of HarfBuzz, a text shaping library.
+ *  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
@@ -18,130 +19,138 @@
  *
  * 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): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_BUFFER_PRIVATE_HH
 #define HB_BUFFER_PRIVATE_HH
 
-#include "hb-private.h"
+#include "hb-private.hh"
 #include "hb-buffer.h"
-#include "hb-unicode-private.h"
+#include "hb-object-private.hh"
+#include "hb-unicode-private.hh"
 
-HB_BEGIN_DECLS
 
 
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
 typedef struct _hb_segment_properties_t {
     hb_direction_t      direction;
     hb_script_t         script;
     hb_language_t       language;
 } hb_segment_properties_t;
 
 
-HB_INTERNAL void
-_hb_buffer_swap (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_clear_output (hb_buffer_t *buffer);
-
-HB_INTERNAL void
-_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
-				unsigned int num_in,
-				unsigned int num_out,
-				const uint16_t *glyph_data_be);
-
-HB_INTERNAL void
-_hb_buffer_replace_glyph (hb_buffer_t *buffer,
-			  hb_codepoint_t glyph_index);
-
-HB_INTERNAL void
-_hb_buffer_next_glyph (hb_buffer_t *buffer);
-
-
-HB_INTERNAL void
-_hb_buffer_reset_masks (hb_buffer_t *buffer,
-			hb_mask_t    mask);
-
-HB_INTERNAL void
-_hb_buffer_add_masks (hb_buffer_t *buffer,
-		      hb_mask_t    mask);
-
-HB_INTERNAL void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
-		      hb_mask_t    value,
-		      hb_mask_t    mask,
-		      unsigned int cluster_start,
-		      unsigned int cluster_end);
-
-
 struct _hb_buffer_t {
-  hb_reference_count_t ref_count;
+  hb_object_header_t header;
 
   /* Information about how the text in the buffer should be treated */
 
   hb_unicode_funcs_t *unicode; /* Unicode functions */
   hb_segment_properties_t props; /* Script, language, direction */
 
   /* Buffer contents */
 
-  unsigned int allocated; /* Length of allocated arrays */
+  bool in_error; /* Allocation failed */
+  bool have_output; /* Whether we have an output buffer going on */
+  bool have_positions; /* Whether we have positions */
 
-  hb_bool_t have_output; /* Whether we have an output buffer going on */
-  hb_bool_t have_positions; /* Whether we have positions */
-  hb_bool_t in_error; /* Allocation failed */
-
-  unsigned int i; /* Cursor into ->info and ->pos arrays */
+  unsigned int idx; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
   unsigned int out_len; /* Length of ->out array if have_output */
 
+  unsigned int allocated; /* Length of allocated arrays */
   hb_glyph_info_t     *info;
   hb_glyph_info_t     *out_info;
   hb_glyph_position_t *pos;
 
-  /* Other stuff */
-
   unsigned int serial;
+  uint8_t allocated_var_bytes[8];
+  const char *allocated_var_owner[8];
 
 
   /* Methods */
+
+  HB_INTERNAL void reset (void);
+
   inline unsigned int backtrack_len (void) const
-  { return this->have_output? this->out_len : this->i; }
+  { return have_output? out_len : idx; }
   inline unsigned int next_serial (void) { return serial++; }
-  inline void swap (void) { _hb_buffer_swap (this); }
-  inline void clear_output (void) { _hb_buffer_clear_output (this); }
-  inline void next_glyph (void) { _hb_buffer_next_glyph (this); }
-  inline void replace_glyphs_be16 (unsigned int num_in,
+
+  HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void deallocate_var_all (void);
+
+  HB_INTERNAL void add (hb_codepoint_t  codepoint,
+			hb_mask_t       mask,
+			unsigned int    cluster);
+
+  HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
+  HB_INTERNAL void reverse (void);
+  HB_INTERNAL void reverse_clusters (void);
+  HB_INTERNAL void guess_properties (void);
+
+  HB_INTERNAL void swap_buffers (void);
+  HB_INTERNAL void clear_output (void);
+  HB_INTERNAL void clear_positions (void);
+  HB_INTERNAL void replace_glyphs_be16 (unsigned int num_in,
+					unsigned int num_out,
+					const uint16_t *glyph_data_be);
+  HB_INTERNAL void replace_glyphs (unsigned int num_in,
 				   unsigned int num_out,
-				   const uint16_t *glyph_data_be)
-  { _hb_buffer_replace_glyphs_be16 (this, num_in, num_out, glyph_data_be); }
-  inline void replace_glyph (hb_codepoint_t glyph_index)
-  { _hb_buffer_replace_glyph (this, glyph_index); }
+				   const uint16_t *glyph_data);
+  HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
+  /* Makes a copy of the glyph at idx to output and replace glyph_index */
+  HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
+  /* Copies glyph at idx to output but doesn't advance idx */
+  HB_INTERNAL void copy_glyph (void);
+  /* Copies glyph at idx to output and advance idx.
+   * If there's no output, just advance idx. */
+  HB_INTERNAL void next_glyph (void);
+  /* Advance idx without copying to output. */
+  inline void skip_glyph (void) { idx++; }
 
   inline void reset_masks (hb_mask_t mask)
   {
-    for (unsigned int i = 0; i < len; i++)
-      info[i].mask = mask;
+    for (unsigned int j = 0; j < len; j++)
+      info[j].mask = mask;
   }
   inline void add_masks (hb_mask_t mask)
   {
-    for (unsigned int i = 0; i < len; i++)
-      info[i].mask |= mask;
+    for (unsigned int j = 0; j < len; j++)
+      info[j].mask |= mask;
   }
-  inline void set_masks (hb_mask_t value,
-			 hb_mask_t mask,
-			 unsigned int cluster_start,
-			 unsigned int cluster_end)
-  { _hb_buffer_set_masks (this, value, mask, cluster_start, cluster_end); }
+  HB_INTERNAL void set_masks (hb_mask_t value,
+			      hb_mask_t mask,
+			      unsigned int cluster_start,
+			      unsigned int cluster_end);
+
+  /* Internal methods */
+  HB_INTERNAL bool enlarge (unsigned int size);
+
+  inline bool ensure (unsigned int size)
+  { return likely (size <= allocated) ? TRUE : enlarge (size); }
+
+  HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+
+  HB_INTERNAL void *get_scratch_buffer (unsigned int *size);
 };
 
 
-HB_END_DECLS
+#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
+  b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
+	   sizeof (b->info[0].var), owner)
+#define HB_BUFFER_ALLOCATE_VAR(b, var) \
+	HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
+#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
+	HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
+
+
 
 #endif /* HB_BUFFER_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -1,13 +1,14 @@
 /*
- * Copyright (C) 1998-2004  David Turner and Werner Lemberg
- * Copyright (C) 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
+ * Copyright © 2011  Google, Inc.
  *
- * This is part of HarfBuzz, a text shaping library.
+ *  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
@@ -18,158 +19,570 @@
  *
  * 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): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-buffer-private.hh"
 
 #include <string.h>
 
-HB_BEGIN_DECLS
+
+
+#ifndef HB_DEBUG_BUFFER
+#define HB_DEBUG_BUFFER (HB_DEBUG+0)
+#endif
 
 
 static hb_buffer_t _hb_buffer_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  HB_OBJECT_HEADER_STATIC,
 
-  &_hb_unicode_funcs_nil  /* unicode */
+  &_hb_unicode_funcs_default,
+  {
+    HB_DIRECTION_INVALID,
+    HB_SCRIPT_INVALID,
+    NULL,
+  },
+
+  TRUE, /* in_error */
+  TRUE, /* have_output */
+  TRUE  /* have_positions */
 };
 
 /* Here is how the buffer works internally:
  *
  * There are two info pointers: info and out_info.  They always have
  * the same allocated size, but different lengths.
  *
  * As an optimization, both info and out_info may point to the
  * same piece of memory, which is owned by info.  This remains the
  * case as long as out_len doesn't exceed i at any time.
- * In that case, swap() is no-op and the glyph operations operate
+ * In that case, swap_buffers() is no-op and the glyph operations operate
  * mostly in-place.
  *
  * As soon as out_info gets longer than info, out_info is moved over
  * to an alternate buffer (which we reuse the pos buffer for!), and its
  * current contents (out_len entries) are copied to the new place.
- * This should all remain transparent to the user.  swap() then
+ * This should all remain transparent to the user.  swap_buffers() then
  * switches info and out_info.
  */
 
 
-static hb_bool_t
-_hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
+
+/* Internal API */
+
+bool
+hb_buffer_t::enlarge (unsigned int size)
 {
-  if (unlikely (buffer->in_error))
+  if (unlikely (in_error))
     return FALSE;
 
-  unsigned int new_allocated = buffer->allocated;
-  hb_glyph_position_t *new_pos;
-  hb_glyph_info_t *new_info;
-  bool separate_out;
+  unsigned int new_allocated = allocated;
+  hb_glyph_position_t *new_pos = NULL;
+  hb_glyph_info_t *new_info = NULL;
+  bool separate_out = out_info != info;
 
-  separate_out = buffer->out_info != buffer->info;
+  if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
+    goto done;
 
   while (size > new_allocated)
-    new_allocated += (new_allocated >> 1) + 8;
+    new_allocated += (new_allocated >> 1) + 32;
+
+  ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
+  if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
+    goto done;
 
-  new_pos = (hb_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
-  new_info = (hb_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
+  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
+  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 
+done:
   if (unlikely (!new_pos || !new_info))
-    buffer->in_error = TRUE;
+    in_error = TRUE;
 
   if (likely (new_pos))
-    buffer->pos = new_pos;
+    pos = new_pos;
 
   if (likely (new_info))
-    buffer->info = new_info;
+    info = new_info;
 
-  buffer->out_info = separate_out ? (hb_glyph_info_t *) buffer->pos : buffer->info;
-  if (likely (!buffer->in_error))
-    buffer->allocated = new_allocated;
+  out_info = separate_out ? (hb_glyph_info_t *) pos : info;
+  if (likely (!in_error))
+    allocated = new_allocated;
 
-  return likely (!buffer->in_error);
+  return likely (!in_error);
 }
 
-static inline hb_bool_t
-_hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
-{
-  return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
-}
-
-static inline hb_bool_t
-_hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
+bool
+hb_buffer_t::make_room_for (unsigned int num_in,
+			    unsigned int num_out)
 {
-  if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE;
+  if (unlikely (!ensure (out_len + num_out))) return FALSE;
 
-  if (buffer->out_info == buffer->info)
+  if (out_info == info &&
+      out_len + num_out > idx + num_in)
   {
-    assert (buffer->have_output);
+    assert (have_output);
 
-    buffer->out_info = (hb_glyph_info_t *) buffer->pos;
-    memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->out_info[0]));
+    out_info = (hb_glyph_info_t *) pos;
+    memcpy (out_info, info, out_len * sizeof (out_info[0]));
   }
 
   return TRUE;
 }
 
+void *
+hb_buffer_t::get_scratch_buffer (unsigned int *size)
+{
+  have_output = FALSE;
+  have_positions = FALSE;
+  out_len = 0;
+  *size = allocated * sizeof (pos[0]);
+  return pos;
+}
+
+
+/* HarfBuzz-Internal API */
+
+void
+hb_buffer_t::reset (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  hb_unicode_funcs_destroy (unicode);
+  unicode = _hb_buffer_nil.unicode;
+
+  props = _hb_buffer_nil.props;
+
+  in_error = FALSE;
+  have_output = FALSE;
+  have_positions = FALSE;
+
+  idx = 0;
+  len = 0;
+  out_len = 0;
+
+  serial = 0;
+  memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
+  memset (allocated_var_owner, 0, sizeof allocated_var_owner);
+
+  out_info = info;
+}
+
+void
+hb_buffer_t::add (hb_codepoint_t  codepoint,
+		  hb_mask_t       mask,
+		  unsigned int    cluster)
+{
+  hb_glyph_info_t *glyph;
+
+  if (unlikely (!ensure (len + 1))) return;
+
+  glyph = &info[len];
+
+  memset (glyph, 0, sizeof (*glyph));
+  glyph->codepoint = codepoint;
+  glyph->mask = mask;
+  glyph->cluster = cluster;
+
+  len++;
+}
+
+void
+hb_buffer_t::clear_output (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = TRUE;
+  have_positions = FALSE;
+
+  out_len = 0;
+  out_info = info;
+}
+
+void
+hb_buffer_t::clear_positions (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = FALSE;
+  have_positions = TRUE;
+
+  memset (pos, 0, sizeof (pos[0]) * len);
+}
+
+void
+hb_buffer_t::swap_buffers (void)
+{
+  if (unlikely (in_error)) return;
+
+  assert (have_output);
+
+  if (out_info != info)
+  {
+    hb_glyph_info_t *tmp_string;
+    tmp_string = info;
+    info = out_info;
+    out_info = tmp_string;
+    pos = (hb_glyph_position_t *) out_info;
+  }
+
+  unsigned int tmp;
+  tmp = len;
+  len = out_len;
+  out_len = tmp;
+
+  idx = 0;
+}
+
+void
+hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
+				  unsigned int num_out,
+				  const uint16_t *glyph_data_be)
+{
+  if (!make_room_for (num_in, num_out)) return;
+
+  hb_glyph_info_t orig_info = info[idx];
+  for (unsigned int i = 1; i < num_in; i++)
+  {
+    hb_glyph_info_t *inf = &info[idx + i];
+    orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
+  }
+
+  hb_glyph_info_t *pinfo = &out_info[out_len];
+  for (unsigned int i = 0; i < num_out; i++)
+  {
+    *pinfo = orig_info;
+    pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]);
+    pinfo++;
+  }
+
+  idx  += num_in;
+  out_len += num_out;
+}
+
+void
+hb_buffer_t::replace_glyphs (unsigned int num_in,
+			     unsigned int num_out,
+			     const uint16_t *glyph_data)
+{
+  if (!make_room_for (num_in, num_out)) return;
+
+  hb_glyph_info_t orig_info = info[idx];
+  for (unsigned int i = 1; i < num_in; i++)
+  {
+    hb_glyph_info_t *inf = &info[idx + i];
+    orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
+  }
+
+  hb_glyph_info_t *pinfo = &out_info[out_len];
+  for (unsigned int i = 0; i < num_out; i++)
+  {
+    *pinfo = orig_info;
+    pinfo->codepoint = glyph_data[i];
+    pinfo++;
+  }
+
+  idx  += num_in;
+  out_len += num_out;
+}
+
+void
+hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
+{
+  if (!make_room_for (0, 1)) return;
+
+  out_info[out_len] = info[idx];
+  out_info[out_len].codepoint = glyph_index;
+
+  out_len++;
+}
+
+void
+hb_buffer_t::copy_glyph (void)
+{
+  if (!make_room_for (0, 1)) return;
+
+  out_info[out_len] = info[idx];
+
+  out_len++;
+}
+
+void
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+{
+  if (!make_room_for (1, 1)) return;
+
+  out_info[out_len] = info[idx];
+  out_info[out_len].codepoint = glyph_index;
+
+  idx++;
+  out_len++;
+}
+
+void
+hb_buffer_t::next_glyph (void)
+{
+  if (have_output)
+  {
+    if (out_info != info)
+    {
+      if (unlikely (!ensure (out_len + 1))) return;
+      out_info[out_len] = info[idx];
+    }
+    else if (out_len != idx)
+      out_info[out_len] = info[idx];
+
+    out_len++;
+  }
+
+  idx++;
+}
+
+void
+hb_buffer_t::set_masks (hb_mask_t    value,
+			hb_mask_t    mask,
+			unsigned int cluster_start,
+			unsigned int cluster_end)
+{
+  hb_mask_t not_mask = ~mask;
+  value &= mask;
+
+  if (!mask)
+    return;
+
+  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      info[i].mask = (info[i].mask & not_mask) | value;
+    return;
+  }
+
+  unsigned int count = len;
+  for (unsigned int i = 0; i < count; i++)
+    if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
+      info[i].mask = (info[i].mask & not_mask) | value;
+}
+
+void
+hb_buffer_t::reverse_range (unsigned int start,
+			    unsigned int end)
+{
+  unsigned int i, j;
+
+  if (start == end - 1)
+    return;
+
+  for (i = start, j = end - 1; i < j; i++, j--) {
+    hb_glyph_info_t t;
+
+    t = info[i];
+    info[i] = info[j];
+    info[j] = t;
+  }
+
+  if (pos) {
+    for (i = start, j = end - 1; i < j; i++, j--) {
+      hb_glyph_position_t t;
+
+      t = pos[i];
+      pos[i] = pos[j];
+      pos[j] = t;
+    }
+  }
+}
+
+void
+hb_buffer_t::reverse (void)
+{
+  if (unlikely (!len))
+    return;
+
+  reverse_range (0, len);
+}
+
+void
+hb_buffer_t::reverse_clusters (void)
+{
+  unsigned int i, start, count, last_cluster;
+
+  if (unlikely (!len))
+    return;
+
+  reverse ();
+
+  count = len;
+  start = 0;
+  last_cluster = info[0].cluster;
+  for (i = 1; i < count; i++) {
+    if (last_cluster != info[i].cluster) {
+      reverse_range (start, i);
+      start = i;
+      last_cluster = info[i].cluster;
+    }
+  }
+  reverse_range (start, i);
+}
+
+void
+hb_buffer_t::guess_properties (void)
+{
+  /* If script is set to INVALID, guess from buffer contents */
+  if (props.script == HB_SCRIPT_INVALID) {
+    for (unsigned int i = 0; i < len; i++) {
+      hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
+      if (likely (script != HB_SCRIPT_COMMON &&
+		  script != HB_SCRIPT_INHERITED &&
+		  script != HB_SCRIPT_UNKNOWN)) {
+        props.script = script;
+        break;
+      }
+    }
+  }
+
+  /* If direction is set to INVALID, guess from script */
+  if (props.direction == HB_DIRECTION_INVALID) {
+    props.direction = hb_script_get_horizontal_direction (props.script);
+  }
+
+  /* If language is not set, use default language from locale */
+  if (props.language == HB_LANGUAGE_INVALID) {
+    /* TODO get_default_for_script? using $LANGUAGE */
+    props.language = hb_language_get_default ();
+  }
+}
+
+
+static inline void
+dump_var_allocation (const hb_buffer_t *buffer)
+{
+  char buf[80];
+  for (unsigned int i = 0; i < 8; i++)
+    buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
+  buf[8] = '\0';
+  DEBUG_MSG (BUFFER, buffer,
+	     "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))
+    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))
+    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::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_t *
-hb_buffer_create (unsigned int pre_alloc_size)
+hb_buffer_create ()
 {
   hb_buffer_t *buffer;
 
-  if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer))
+  if (!(buffer = hb_object_create<hb_buffer_t> ()))
     return &_hb_buffer_nil;
 
-  if (pre_alloc_size)
-    _hb_buffer_ensure (buffer, pre_alloc_size);
-
-  buffer->unicode = &_hb_unicode_funcs_nil;
+  buffer->reset ();
 
   return buffer;
 }
 
 hb_buffer_t *
-hb_buffer_reference (hb_buffer_t *buffer)
+hb_buffer_get_empty (void)
 {
-  HB_OBJECT_DO_REFERENCE (buffer);
+  return &_hb_buffer_nil;
 }
 
-unsigned int
-hb_buffer_get_reference_count (hb_buffer_t *buffer)
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer)
 {
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer);
+  return hb_object_reference (buffer);
 }
 
 void
 hb_buffer_destroy (hb_buffer_t *buffer)
 {
-  HB_OBJECT_DO_DESTROY (buffer);
+  if (!hb_object_destroy (buffer)) return;
 
   hb_unicode_funcs_destroy (buffer->unicode);
 
   free (buffer->info);
   free (buffer->pos);
 
   free (buffer);
 }
 
+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);
+}
+
+void *
+hb_buffer_get_user_data (hb_buffer_t        *buffer,
+			 hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (buffer, key);
+}
+
 
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
 			     hb_unicode_funcs_t *unicode)
 {
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
   if (!unicode)
-    unicode = &_hb_unicode_funcs_nil;
+    unicode = _hb_buffer_nil.unicode;
 
   hb_unicode_funcs_reference (unicode);
   hb_unicode_funcs_destroy (buffer->unicode);
   buffer->unicode = unicode;
 }
 
 hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
@@ -177,356 +590,175 @@ hb_buffer_get_unicode_funcs (hb_buffer_t
   return buffer->unicode;
 }
 
 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_direction_t
 hb_buffer_get_direction (hb_buffer_t    *buffer)
 {
   return buffer->props.direction;
 }
 
 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_script_t
 hb_buffer_get_script (hb_buffer_t *buffer)
 {
   return buffer->props.script;
 }
 
 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_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
 {
   return buffer->props.language;
 }
 
 
 void
-hb_buffer_clear (hb_buffer_t *buffer)
+hb_buffer_reset (hb_buffer_t *buffer)
 {
-  buffer->have_output = FALSE;
-  buffer->have_positions = FALSE;
-  buffer->in_error = FALSE;
-  buffer->len = 0;
-  buffer->out_len = 0;
-  buffer->i = 0;
-  buffer->out_info = buffer->info;
-  buffer->serial = 0;
+  buffer->reset ();
 }
 
 hb_bool_t
-hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
-{
-  return _hb_buffer_ensure (buffer, size);
-}
-
-void
-hb_buffer_add_glyph (hb_buffer_t    *buffer,
-		     hb_codepoint_t  codepoint,
-		     hb_mask_t       mask,
-		     unsigned int    cluster)
+hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
 {
-  hb_glyph_info_t *glyph;
-
-  if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
-
-  glyph = &buffer->info[buffer->len];
-
-  memset (glyph, 0, sizeof (*glyph));
-  glyph->codepoint = codepoint;
-  glyph->mask = mask;
-  glyph->cluster = cluster;
-
-  buffer->len++;
+  return buffer->ensure (size);
 }
 
-void
-hb_buffer_clear_positions (hb_buffer_t *buffer)
-{
-  _hb_buffer_clear_output (buffer);
-  buffer->have_output = FALSE;
-  buffer->have_positions = TRUE;
-
-  if (unlikely (!buffer->pos))
-  {
-    buffer->pos = (hb_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
-    return;
-  }
-
-  memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
-}
-
-/* HarfBuzz-Internal API */
-
-void
-_hb_buffer_clear_output (hb_buffer_t *buffer)
+hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer)
 {
-  buffer->have_output = TRUE;
-  buffer->have_positions = FALSE;
-  buffer->out_len = 0;
-  buffer->out_info = buffer->info;
-}
-
-void
-_hb_buffer_swap (hb_buffer_t *buffer)
-{
-  unsigned int tmp;
-
-  assert (buffer->have_output);
-
-  if (unlikely (buffer->in_error)) return;
-
-  if (buffer->out_info != buffer->info)
-  {
-    hb_glyph_info_t *tmp_string;
-    tmp_string = buffer->info;
-    buffer->info = buffer->out_info;
-    buffer->out_info = tmp_string;
-    buffer->pos = (hb_glyph_position_t *) buffer->out_info;
-  }
-
-  tmp = buffer->len;
-  buffer->len = buffer->out_len;
-  buffer->out_len = tmp;
-
-  buffer->i = 0;
+  return !buffer->in_error;
 }
 
 void
-_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer,
-				unsigned int num_in,
-				unsigned int num_out,
-				const uint16_t *glyph_data_be)
+hb_buffer_add (hb_buffer_t    *buffer,
+	       hb_codepoint_t  codepoint,
+	       hb_mask_t       mask,
+	       unsigned int    cluster)
 {
-  if (buffer->out_info != buffer->info ||
-      buffer->out_len + num_out > buffer->i + num_in)
-  {
-    if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
-      return;
-  }
-
-  hb_glyph_info_t orig_info = buffer->info[buffer->i];
-
-  for (unsigned int i = 0; i < num_out; i++)
-  {
-    hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
-    *info = orig_info;
-    info->codepoint = hb_be_uint16 (glyph_data_be[i]);
-  }
-
-  buffer->i  += num_in;
-  buffer->out_len += num_out;
-}
-
-void
-_hb_buffer_replace_glyph (hb_buffer_t *buffer,
-			  hb_codepoint_t glyph_index)
-{
-  hb_glyph_info_t *info;
-
-  if (buffer->out_info != buffer->info)
-  {
-    if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
-    buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-  }
-  else if (buffer->out_len != buffer->i)
-    buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-
-  info = &buffer->out_info[buffer->out_len];
-  info->codepoint = glyph_index;
-
-  buffer->i++;
-  buffer->out_len++;
+  buffer->add (codepoint, mask, cluster);
 }
 
-void
-_hb_buffer_next_glyph (hb_buffer_t *buffer)
+hb_bool_t
+hb_buffer_set_length (hb_buffer_t  *buffer,
+		      unsigned int  length)
 {
-  if (buffer->have_output)
-  {
-    if (buffer->out_info != buffer->info)
-    {
-      if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
-      buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
-    }
-    else if (buffer->out_len != buffer->i)
-      buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
+  if (!buffer->ensure (length))
+    return FALSE;
 
-    buffer->out_len++;
+  /* Wipe the new space */
+  if (length > buffer->len) {
+    memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len));
+    if (buffer->have_positions)
+      memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len));
   }
 
-  buffer->i++;
-}
-
-void
-_hb_buffer_reset_masks (hb_buffer_t *buffer,
-			hb_mask_t    mask)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask = mask;
-}
-
-void
-_hb_buffer_add_masks (hb_buffer_t *buffer,
-		      hb_mask_t    mask)
-{
-  unsigned int count = buffer->len;
-  for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask |= mask;
+  buffer->len = length;
+  return TRUE;
 }
 
-void
-_hb_buffer_set_masks (hb_buffer_t *buffer,
-		      hb_mask_t    value,
-		      hb_mask_t    mask,
-		      unsigned int cluster_start,
-		      unsigned int cluster_end)
-{
-  hb_mask_t not_mask = ~mask;
-  value &= mask;
-
-  if (!mask)
-    return;
-
-  if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
-    unsigned int count = buffer->len;
-    for (unsigned int i = 0; i < count; i++)
-      buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
-    return;
-  }
-
-  /* XXX can't bsearch since .cluster may not be sorted. */
-  /* Binary search to find the start position and go from there. */
-  unsigned int min = 0, max = buffer->len;
-  while (min < max)
-  {
-    unsigned int mid = min + ((max - min) / 2);
-    if (buffer->info[mid].cluster < cluster_start)
-      min = mid + 1;
-    else
-      max = mid;
-  }
-  unsigned int count = buffer->len;
-  for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++)
-    buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
-}
-
-
-/* Public API again */
-
 unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer)
 {
   return buffer->len;
 }
 
 /* Return value valid as long as buffer not modified */
 hb_glyph_info_t *
-hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
+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_glyph_position_t *
-hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
+hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
+                               unsigned int *length)
 {
   if (!buffer->have_positions)
-    hb_buffer_clear_positions (buffer);
+    buffer->clear_positions ();
+
+  if (length)
+    *length = buffer->len;
 
   return (hb_glyph_position_t *) buffer->pos;
 }
 
-
-static void
-reverse_range (hb_buffer_t *buffer,
-	       unsigned int start,
-	       unsigned int end)
-{
-  hb_glyph_info_t *i = buffer->info + start;
-  hb_glyph_info_t *j = buffer->info + end - 1;
-  while (i < j) {
-    hb_glyph_info_t t = *i;
-    *i++ = *j;
-    *j-- = t;
-  }
-
-  if (buffer->pos) {
-    hb_glyph_position_t *ii = buffer->pos + start;
-    hb_glyph_position_t *jj = buffer->pos + end - 1;
-    while (ii < jj) {
-      hb_glyph_position_t tt = *ii;
-      *ii++ = *jj;
-      *jj-- = tt;
-    }
-  }
-}
-
 void
 hb_buffer_reverse (hb_buffer_t *buffer)
 {
-  if (unlikely (!buffer->len))
-    return;
-
-  reverse_range (buffer, 0, buffer->len);
+  buffer->reverse ();
 }
 
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
 {
-  unsigned int i, start, count, last_cluster;
-
-  if (unlikely (!buffer->len))
-    return;
-
-  hb_buffer_reverse (buffer);
-
-  count = buffer->len;
-  start = 0;
-  last_cluster = buffer->info[0].cluster;
-  for (i = 1; i < count; i++) {
-    if (last_cluster != buffer->info[i].cluster) {
-      reverse_range (buffer, start, i);
-      start = i;
-      last_cluster = buffer->info[i].cluster;
-    }
-  }
-  reverse_range (buffer, start, i);
+  buffer->reverse_clusters ();
 }
 
+void
+hb_buffer_guess_properties (hb_buffer_t *buffer)
+{
+  buffer->guess_properties ();
+}
 
 #define ADD_UTF(T) \
 	HB_STMT_START { \
+	  if (text_length == -1) { \
+	    text_length = 0; \
+	    const T *p = (const T *) text; \
+	    while (*p) { \
+	      text_length++; \
+	      p++; \
+	    } \
+	  } \
+	  if (item_length == -1) \
+	    item_length = text_length - item_offset; \
+	  buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \
 	  const T *next = (const T *) text + item_offset; \
 	  const T *end = next + item_length; \
 	  while (next < end) { \
 	    hb_codepoint_t u; \
 	    const T *old_next = next; \
 	    next = UTF_NEXT (next, end, u); \
-	    hb_buffer_add_glyph (buffer, u, 1,  old_next - (const T *) text); \
+	    hb_buffer_add (buffer, u, 1,  old_next - (const T *) text); \
 	  } \
 	} HB_STMT_END
 
 
 #define UTF8_COMPUTE(Char, Mask, Len) \
   if (Char < 128) { Len = 1; Mask = 0x7f; } \
   else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
   else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
@@ -536,17 +768,17 @@ hb_buffer_reverse_clusters (hb_buffer_t 
 static inline const uint8_t *
 hb_utf8_next (const uint8_t *text,
 	      const uint8_t *end,
 	      hb_codepoint_t *unicode)
 {
   uint8_t c = *text;
   unsigned int mask, len;
 
-  /* TODO check for overlong sequences?  also: optimize? */
+  /* TODO check for overlong sequences? */
 
   UTF8_COMPUTE (c, mask, len);
   if (unlikely (!len || (unsigned int) (end - text) < len)) {
     *unicode = -1;
     return text + 1;
   } else {
     hb_codepoint_t result;
     unsigned int i;
@@ -564,65 +796,64 @@ hb_utf8_next (const uint8_t *text,
     *unicode = result;
     return text + len;
   }
 }
 
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
 		    const char   *text,
-		    unsigned int  text_length HB_UNUSED,
+		    int           text_length,
 		    unsigned int  item_offset,
-		    unsigned int  item_length)
+		    int           item_length)
 {
 #define UTF_NEXT(S, E, U)	hb_utf8_next (S, E, &(U))
   ADD_UTF (uint8_t);
 #undef UTF_NEXT
 }
 
 static inline const uint16_t *
 hb_utf16_next (const uint16_t *text,
 	       const uint16_t *end,
 	       hb_codepoint_t *unicode)
 {
   uint16_t c = *text++;
 
   if (unlikely (c >= 0xd800 && c < 0xdc00)) {
     /* high surrogate */
     uint16_t l;
-    if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) {
+    if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
       /* low surrogate */
       *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
        text++;
     } else
       *unicode = -1;
   } else
     *unicode = c;
 
   return text;
 }
 
 void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
 		     const uint16_t *text,
-		     unsigned int    text_length HB_UNUSED,
+		     int             text_length,
 		     unsigned int    item_offset,
-		     unsigned int    item_length)
+		     int            item_length)
 {
 #define UTF_NEXT(S, E, U)	hb_utf16_next (S, E, &(U))
   ADD_UTF (uint16_t);
 #undef UTF_NEXT
 }
 
 void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
 		     const uint32_t *text,
-		     unsigned int    text_length HB_UNUSED,
+		     int             text_length,
 		     unsigned int    item_offset,
-		     unsigned int    item_length)
+		     int             item_length)
 {
 #define UTF_NEXT(S, E, U)	((U) = *(S), (S)+1)
   ADD_UTF (uint32_t);
 #undef UTF_NEXT
 }
 
 
-HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -1,13 +1,14 @@
 /*
- * Copyright (C) 1998-2004  David Turner and Werner Lemberg
- * Copyright (C) 2004,2007,2009  Red Hat, Inc.
+ * Copyright © 1998-2004  David Turner and Werner Lemberg
+ * Copyright © 2004,2007,2009  Red Hat, Inc.
+ * Copyright © 2011  Google, Inc.
  *
- * This is part of HarfBuzz, a text shaping library.
+ *  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
@@ -18,59 +19,74 @@
  *
  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_BUFFER_H
 #define HB_BUFFER_H
 
 #include "hb-common.h"
 #include "hb-unicode.h"
-#include "hb-language.h"
 
 HB_BEGIN_DECLS
 
 
 typedef struct _hb_buffer_t hb_buffer_t;
 
 typedef struct _hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
   uint32_t       cluster;
+
+  /*< private >*/
   hb_var_int_t   var1;
   hb_var_int_t   var2;
 } hb_glyph_info_t;
 
 typedef struct _hb_glyph_position_t {
   hb_position_t  x_advance;
   hb_position_t  y_advance;
   hb_position_t  x_offset;
   hb_position_t  y_offset;
+
+  /*< private >*/
   hb_var_int_t   var;
 } hb_glyph_position_t;
 
 
 hb_buffer_t *
-hb_buffer_create (unsigned int pre_alloc_size);
+hb_buffer_create (void);
+
+hb_buffer_t *
+hb_buffer_get_empty (void);
 
 hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer);
 
-unsigned int
-hb_buffer_get_reference_count (hb_buffer_t *buffer);
-
 void
 hb_buffer_destroy (hb_buffer_t *buffer);
 
+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);
+
+void *
+hb_buffer_get_user_data (hb_buffer_t        *buffer,
+			 hb_user_data_key_t *key);
+
 
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
 			     hb_unicode_funcs_t *unicode_funcs);
 
 hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer);
 
@@ -91,73 +107,88 @@ hb_buffer_get_script (hb_buffer_t *buffe
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
 			hb_language_t  language);
 
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer);
 
 
-void
-hb_buffer_clear (hb_buffer_t *buffer);
-
+/* Resets the buffer.  Afterwards it's as if it was just created,
+ * except that it has a larger buffer allocated perhaps... */
 void
-hb_buffer_clear_positions (hb_buffer_t *buffer);
+hb_buffer_reset (hb_buffer_t *buffer);
 
+/* Returns FALSE if allocation failed */
 hb_bool_t
-hb_buffer_ensure (hb_buffer_t  *buffer,
-		  unsigned int  size);
+hb_buffer_pre_allocate (hb_buffer_t  *buffer,
+		        unsigned int  size);
+
+
+/* Returns FALSE if allocation has failed before */
+hb_bool_t
+hb_buffer_allocation_successful (hb_buffer_t  *buffer);
 
 void
 hb_buffer_reverse (hb_buffer_t *buffer);
 
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer);
 
+void
+hb_buffer_guess_properties (hb_buffer_t *buffer);
+
 
 /* Filling the buffer in */
 
 void
-hb_buffer_add_glyph (hb_buffer_t    *buffer,
-		     hb_codepoint_t  codepoint,
-		     hb_mask_t       mask,
-		     unsigned int    cluster);
+hb_buffer_add (hb_buffer_t    *buffer,
+	       hb_codepoint_t  codepoint,
+	       hb_mask_t       mask,
+	       unsigned int    cluster);
 
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
 		    const char   *text,
-		    unsigned int  text_length,
+		    int           text_length,
 		    unsigned int  item_offset,
-		    unsigned int  item_length);
+		    int           item_length);
 
 void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
 		     const uint16_t *text,
-		     unsigned int    text_length,
+		     int             text_length,
 		     unsigned int    item_offset,
-		     unsigned int    item_length);
+		     int             item_length);
 
 void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
 		     const uint32_t *text,
-		     unsigned int    text_length,
+		     int             text_length,
 		     unsigned int    item_offset,
-		     unsigned int    item_length);
+		     int             item_length);
 
 
-/* Getting glyphs out of the buffer */
+/* Clears any new items added at the end */
+hb_bool_t
+hb_buffer_set_length (hb_buffer_t  *buffer,
+		      unsigned int  length);
 
 /* Return value valid as long as buffer not modified */
 unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer);
 
+/* Getting glyphs out of the buffer */
+
 /* Return value valid as long as buffer not modified */
 hb_glyph_info_t *
-hb_buffer_get_glyph_infos (hb_buffer_t *buffer);
+hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
+                           unsigned int *length);
 
 /* Return value valid as long as buffer not modified */
 hb_glyph_position_t *
-hb_buffer_get_glyph_positions (hb_buffer_t *buffer);
+hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
+                               unsigned int *length);
 
 
 HB_END_DECLS
 
 #endif /* HB_BUFFER_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-common.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2010  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-HB_BEGIN_DECLS
-
-
-hb_tag_t
-hb_tag_from_string (const char *s)
-{
-  char tag[4];
-  unsigned int i;
-
-  for (i = 0; i < 4 && s[i]; i++)
-    tag[i] = s[i];
-  for (; i < 4; i++)
-    tag[i] = ' ';
-
-  return HB_TAG_STR (tag);
-}
-
-
-HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -0,0 +1,372 @@
+/*
+ * Copyright © 2009,2010  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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-version.h"
+
+#include "hb-mutex-private.hh"
+#include "hb-object-private.hh"
+
+#include <locale.h>
+
+
+
+/* hb_tag_t */
+
+hb_tag_t
+hb_tag_from_string (const char *s, int len)
+{
+  char tag[4];
+  unsigned int i;
+
+  if (!s || !len || !*s)
+    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 < 4; i++)
+    tag[i] = ' ';
+
+  return HB_TAG_CHAR4 (tag);
+}
+
+
+/* hb_direction_t */
+
+const char direction_strings[][4] = {
+  "ltr",
+  "rtl",
+  "ttb",
+  "btt"
+};
+
+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!
+   */
+  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) i;
+
+  return HB_DIRECTION_INVALID;
+}
+
+const char *
+hb_direction_to_string (hb_direction_t direction)
+{
+  if (likely ((unsigned int) direction < ARRAY_LENGTH (direction_strings)))
+    return direction_strings[direction];
+
+  return "invalid";
+}
+
+
+/* hb_language_t */
+
+struct _hb_language_t {
+  const char s[1];
+};
+
+static const char canon_map[256] = {
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
+   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
+  '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
+  '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
+   0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
+};
+
+static hb_bool_t
+lang_equal (const void *v1,
+	    const void *v2)
+{
+  const unsigned char *p1 = (const unsigned char *) v1;
+  const unsigned char *p2 = (const unsigned char *) v2;
+
+  while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
+    {
+      p1++, p2++;
+    }
+
+  return (canon_map[*p1] == canon_map[*p2]);
+}
+
+#if 0
+static unsigned int
+lang_hash (const void *key)
+{
+  const unsigned char *p = key;
+  unsigned int h = 0;
+  while (canon_map[*p])
+    {
+      h = (h << 5) - h + canon_map[*p];
+      p++;
+    }
+
+  return h;
+}
+#endif
+
+
+struct hb_language_item_t {
+
+  hb_language_t lang;
+
+  inline bool operator == (const char *s) const {
+    return lang_equal (lang, s);
+  }
+
+  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); }
+};
+
+static struct hb_static_lang_set_t : hb_lockable_set_t<hb_language_item_t, hb_static_mutex_t> {
+  ~hb_static_lang_set_t (void) { this->finish (lock); }
+  hb_static_mutex_t lock;
+} langs;
+
+hb_language_t
+hb_language_from_string (const char *str, int len)
+{
+  if (!str || !len || !*str)
+    return HB_LANGUAGE_INVALID;
+
+  char strbuf[32];
+  if (len >= 0) {
+    len = MIN (len, (int) sizeof (strbuf) - 1);
+    str = (char *) memcpy (strbuf, str, len);
+    strbuf[len] = '\0';
+  }
+
+  hb_language_item_t *item = langs.find_or_insert (str, langs.lock);
+
+  return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
+}
+
+const char *
+hb_language_to_string (hb_language_t language)
+{
+  /* This is actually NULL-safe! */
+  return language->s;
+}
+
+hb_language_t
+hb_language_get_default (void)
+{
+  static hb_language_t default_language;
+
+  if (!default_language) {
+    /* This block is not quite threadsafe, but is not as bad as
+     * it looks since it's idempotent.  As long as pointer ops
+     * are atomic, we are safe. */
+
+    /* I hear that setlocale() doesn't honor env vars on Windows,
+     * but for now we ignore that. */
+
+    default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+  }
+
+  return default_language;
+}
+
+
+/* hb_script_t */
+
+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;
+
+  switch (tag) {
+
+    /* These graduated from the 'Q' private-area codes, but
+     * the old code is still aliased by Unicode, and the Qaai
+     * one in use by ICU. */
+    case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
+    case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
+
+    /* Script variants from http://unicode.org/iso15924/ */
+    case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
+    case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
+    case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
+    case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
+    case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
+    case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
+  }
+
+  /* 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_t
+hb_script_from_string (const char *s, int len)
+{
+  return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
+}
+
+hb_tag_t
+hb_script_to_iso15924_tag (hb_script_t script)
+{
+  return (hb_tag_t) script;
+}
+
+hb_direction_t
+hb_script_get_horizontal_direction (hb_script_t script)
+{
+  switch ((hb_tag_t) script)
+  {
+    case HB_SCRIPT_ARABIC:
+    case HB_SCRIPT_HEBREW:
+    case HB_SCRIPT_SYRIAC:
+    case HB_SCRIPT_THAANA:
+
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_CYPRIOT:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_PHOENICIAN:
+    case HB_SCRIPT_NKO:
+
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_AVESTAN:
+    case HB_SCRIPT_IMPERIAL_ARAMAIC:
+    case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
+    case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
+    case HB_SCRIPT_OLD_SOUTH_ARABIAN:
+    case HB_SCRIPT_OLD_TURKIC:
+    case HB_SCRIPT_SAMARITAN:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
+      return HB_DIRECTION_RTL;
+  }
+
+  return HB_DIRECTION_LTR;
+}
+
+
+/* hb_user_data_array_t */
+
+
+/* NOTE: Currently we use a global lock for user_data access
+ * threadsafety.  If one day we add a mutex to any object, we
+ * should switch to using that insted for these too.
+ */
+
+static hb_static_mutex_t user_data_lock;
+
+bool
+hb_user_data_array_t::set (hb_user_data_key_t *key,
+			   void *              data,
+			   hb_destroy_func_t   destroy,
+			   hb_bool_t           replace)
+{
+  if (!key)
+    return false;
+
+  if (replace) {
+    if (!data && !destroy) {
+      items.remove (key, user_data_lock);
+      return true;
+    }
+  }
+  hb_user_data_item_t item = {key, data, destroy};
+  bool ret = !!items.replace_or_insert (item, user_data_lock, replace);
+
+  return ret;
+}
+
+void *
+hb_user_data_array_t::get (hb_user_data_key_t *key)
+{
+  hb_user_data_item_t item = {NULL };
+
+  return items.find (key, &item, user_data_lock) ? item.data : NULL;
+}
+
+void
+hb_user_data_array_t::finish (void)
+{
+  items.finish (user_data_lock);
+}
+
+
+/* hb_version */
+
+void
+hb_version (unsigned int *major,
+	    unsigned int *minor,
+	    unsigned int *micro)
+{
+  *major = HB_VERSION_MAJOR;
+  *minor = HB_VERSION_MINOR;
+  *micro = HB_VERSION_MICRO;
+}
+
+const char *
+hb_version_string (void)
+{
+  return HB_VERSION_STRING;
+}
+
+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
@@ -1,10 +1,11 @@
 /*
- * Copyright (C) 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2007,2008,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.
@@ -17,90 +18,314 @@
  *
  * 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_COMMON_H
 #define HB_COMMON_H
 
 # ifdef __cplusplus
 #  define HB_BEGIN_DECLS	extern "C" {
 #  define HB_END_DECLS		}
 # else /* !__cplusplus */
 #  define HB_BEGIN_DECLS
 #  define HB_END_DECLS
 # endif /* !__cplusplus */
 
 HB_BEGIN_DECLS
 
+#if !defined (HB_DONT_DEFINE_STDINT)
 
-#ifdef _MSC_VER
-#define _HB__STR2__(x) #x
-#define _HB__STR1__(x) _HB__STR2__(x)
-#define _HB__LOC__ __FILE__ "("_HB__STR1__(__LINE__)") : Warning Msg: "
-#pragma message(_HB__LOC__"Not using stdint.h; integer types may have wrong size")
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#ifndef __cplusplus
-#define inline __inline
-#endif
+#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
+    defined (_sgi) || defined (__sun) || defined (sun) || \
+    defined (__digital__) || defined (__HP_cc)
+#  include <inttypes.h>
+#elif defined (_AIX)
+#  include <sys/inttypes.h>
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
+#elif defined (_MSC_VER) && _MSC_VER < 1600
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
 #else
-#include <stdint.h>
+#  include <stdint.h>
 #endif
 
-typedef int hb_bool_t;
+#endif
 
-typedef uint32_t hb_tag_t;
-#define HB_TAG(a,b,c,d) ((hb_tag_t)(((uint8_t)a<<24)|((uint8_t)b<<16)|((uint8_t)c<<8)|(uint8_t)d))
-#define HB_TAG_STR(s)   (HB_TAG(((const char *) s)[0], \
-				((const char *) s)[1], \
-				((const char *) s)[2], \
-				((const char *) s)[3]))
-#define HB_TAG_NONE HB_TAG(0,0,0,0)
 
-hb_tag_t hb_tag_from_string (const char *s);
-
+typedef int hb_bool_t;
 
 typedef uint32_t hb_codepoint_t;
 typedef int32_t hb_position_t;
 typedef uint32_t hb_mask_t;
 
-typedef void (*hb_destroy_func_t) (void *user_data);
-
-typedef enum _hb_direction_t {
-  HB_DIRECTION_LTR,
-  HB_DIRECTION_RTL,
-  HB_DIRECTION_TTB,
-  HB_DIRECTION_BTT
-} hb_direction_t;
-
-#define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 0)
-#define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 2)
-#define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 0)
-#define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 1)
-#define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1))
-
-
 typedef union _hb_var_int_t {
   uint32_t u32;
   int32_t i32;
   uint16_t u16[2];
   int16_t i16[2];
   uint8_t u8[4];
   int8_t i8[4];
 } hb_var_int_t;
 
 
+/* hb_tag_t */
+
+typedef uint32_t hb_tag_t;
+
+#define HB_TAG(a,b,c,d) ((hb_tag_t)((((uint8_t)(a))<<24)|(((uint8_t)(b))<<16)|(((uint8_t)(c))<<8)|((uint8_t)(d))))
+#define HB_UNTAG(tag)   ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
+
+#define HB_TAG_NONE HB_TAG(0,0,0,0)
+
+/* len=-1 means s is NUL-terminated */
+hb_tag_t hb_tag_from_string (const char *s, int len);
+
+
+/* hb_direction_t */
+
+typedef enum {
+  HB_DIRECTION_INVALID = -1,
+  HB_DIRECTION_LTR = 0,
+  HB_DIRECTION_RTL,
+  HB_DIRECTION_TTB,
+  HB_DIRECTION_BTT
+} hb_direction_t;
+
+/* len=-1 means s is NUL-terminated */
+hb_direction_t
+hb_direction_from_string (const char *str, int len);
+
+const char *
+hb_direction_to_string (hb_direction_t direction);
+
+#define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 0)
+#define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 2)
+#define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 0)
+#define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 1)
+#define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1))
+
+
+/* hb_language_t */
+
+typedef struct _hb_language_t *hb_language_t;
+
+/* len=-1 means s 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);
+
+#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+
+hb_language_t
+hb_language_get_default (void);
+
+
+/* hb_unicode_general_category_t */
+
+typedef enum
+{
+  HB_UNICODE_GENERAL_CATEGORY_CONTROL,			/* Cc */
+  HB_UNICODE_GENERAL_CATEGORY_FORMAT,			/* Cf */
+  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,		/* Cn */
+  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,		/* Co */
+  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,		/* Cs */
+  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,		/* Ll */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,		/* Lm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,		/* Lo */
+  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,		/* Lt */
+  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,		/* Lu */
+  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,		/* Mc */
+  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,		/* Me */
+  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,		/* Mn */
+  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,		/* Nd */
+  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,		/* Nl */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,		/* No */
+  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,	/* Pc */
+  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,		/* Pd */
+  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,	/* Pe */
+  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,	/* Pf */
+  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,	/* Pi */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,	/* Po */
+  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,		/* Ps */
+  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,		/* Sc */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,		/* Sk */
+  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,		/* Sm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,		/* So */
+  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,		/* Zl */
+  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,	/* Zp */
+  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR		/* Zs */
+} hb_unicode_general_category_t;
+
+
+/* hb_script_t */
+
+/* http://unicode.org/iso15924/ */
+typedef enum
+{
+  HB_SCRIPT_COMMON                  = HB_TAG ('Z','y','y','y'),
+  HB_SCRIPT_INHERITED               = HB_TAG ('Z','i','n','h'),
+  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_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_DESERET                 = HB_TAG ('D','s','r','t'),
+  HB_SCRIPT_DEVANAGARI              = HB_TAG ('D','e','v','a'),
+  HB_SCRIPT_ETHIOPIC                = HB_TAG ('E','t','h','i'),
+  HB_SCRIPT_GEORGIAN                = HB_TAG ('G','e','o','r'),
+  HB_SCRIPT_GOTHIC                  = HB_TAG ('G','o','t','h'),
+  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_HAN                     = HB_TAG ('H','a','n','i'),
+  HB_SCRIPT_HANGUL                  = HB_TAG ('H','a','n','g'),
+  HB_SCRIPT_HEBREW                  = HB_TAG ('H','e','b','r'),
+  HB_SCRIPT_HIRAGANA                = HB_TAG ('H','i','r','a'),
+  HB_SCRIPT_KANNADA                 = HB_TAG ('K','n','d','a'),
+  HB_SCRIPT_KATAKANA                = HB_TAG ('K','a','n','a'),
+  HB_SCRIPT_KHMER                   = HB_TAG ('K','h','m','r'),
+  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_MYANMAR                 = HB_TAG ('M','y','m','r'),
+  HB_SCRIPT_OGHAM                   = HB_TAG ('O','g','a','m'),
+  HB_SCRIPT_OLD_ITALIC              = HB_TAG ('I','t','a','l'),
+  HB_SCRIPT_ORIYA                   = HB_TAG ('O','r','y','a'),
+  HB_SCRIPT_RUNIC                   = HB_TAG ('R','u','n','r'),
+  HB_SCRIPT_SINHALA                 = HB_TAG ('S','i','n','h'),
+  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_THAANA                  = HB_TAG ('T','h','a','a'),
+  HB_SCRIPT_THAI                    = HB_TAG ('T','h','a','i'),
+  HB_SCRIPT_TIBETAN                 = HB_TAG ('T','i','b','t'),
+  HB_SCRIPT_CANADIAN_ABORIGINAL     = HB_TAG ('C','a','n','s'),
+  HB_SCRIPT_YI                      = HB_TAG ('Y','i','i','i'),
+  HB_SCRIPT_TAGALOG                 = HB_TAG ('T','g','l','g'),
+  HB_SCRIPT_HANUNOO                 = HB_TAG ('H','a','n','o'),
+  HB_SCRIPT_BUHID                   = HB_TAG ('B','u','h','d'),
+  HB_SCRIPT_TAGBANWA                = HB_TAG ('T','a','g','b'),
+
+  /* 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_OSMANYA                 = HB_TAG ('O','s','m','a'),
+  HB_SCRIPT_SHAVIAN                 = HB_TAG ('S','h','a','w'),
+  HB_SCRIPT_LINEAR_B                = HB_TAG ('L','i','n','b'),
+  HB_SCRIPT_TAI_LE                  = HB_TAG ('T','a','l','e'),
+  HB_SCRIPT_UGARITIC                = HB_TAG ('U','g','a','r'),
+
+  /* Unicode-4.1 additions */
+  HB_SCRIPT_NEW_TAI_LUE             = HB_TAG ('T','a','l','u'),
+  HB_SCRIPT_BUGINESE                = HB_TAG ('B','u','g','i'),
+  HB_SCRIPT_GLAGOLITIC              = HB_TAG ('G','l','a','g'),
+  HB_SCRIPT_TIFINAGH                = HB_TAG ('T','f','n','g'),
+  HB_SCRIPT_SYLOTI_NAGRI            = HB_TAG ('S','y','l','o'),
+  HB_SCRIPT_OLD_PERSIAN             = HB_TAG ('X','p','e','o'),
+  HB_SCRIPT_KHAROSHTHI              = HB_TAG ('K','h','a','r'),
+
+  /* Unicode-5.0 additions */
+  HB_SCRIPT_UNKNOWN                 = HB_TAG ('Z','z','z','z'),
+  HB_SCRIPT_BALINESE                = HB_TAG ('B','a','l','i'),
+  HB_SCRIPT_CUNEIFORM               = HB_TAG ('X','s','u','x'),
+  HB_SCRIPT_PHOENICIAN              = HB_TAG ('P','h','n','x'),
+  HB_SCRIPT_PHAGS_PA                = HB_TAG ('P','h','a','g'),
+  HB_SCRIPT_NKO                     = HB_TAG ('N','k','o','o'),
+
+  /* Unicode-5.1 additions */
+  HB_SCRIPT_KAYAH_LI                = HB_TAG ('K','a','l','i'),
+  HB_SCRIPT_LEPCHA                  = HB_TAG ('L','e','p','c'),
+  HB_SCRIPT_REJANG                  = HB_TAG ('R','j','n','g'),
+  HB_SCRIPT_SUNDANESE               = HB_TAG ('S','u','n','d'),
+  HB_SCRIPT_SAURASHTRA              = HB_TAG ('S','a','u','r'),
+  HB_SCRIPT_CHAM                    = HB_TAG ('C','h','a','m'),
+  HB_SCRIPT_OL_CHIKI                = HB_TAG ('O','l','c','k'),
+  HB_SCRIPT_VAI                     = HB_TAG ('V','a','i','i'),
+  HB_SCRIPT_CARIAN                  = HB_TAG ('C','a','r','i'),
+  HB_SCRIPT_LYCIAN                  = HB_TAG ('L','y','c','i'),
+  HB_SCRIPT_LYDIAN                  = HB_TAG ('L','y','d','i'),
+
+  /* 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;
+
+
+/* Script functions */
+
+hb_script_t
+hb_script_from_iso15924_tag (hb_tag_t tag);
+
+/* suger for tag_from_string() then script_from_iso15924_tag */
+/* len=-1 means s is NUL-terminated */
+hb_script_t
+hb_script_from_string (const char *s, int len);
+
+hb_tag_t
+hb_script_to_iso15924_tag (hb_script_t script);
+
+hb_direction_t
+hb_script_get_horizontal_direction (hb_script_t script);
+
+
+/* User data */
+
+typedef struct _hb_user_data_key_t {
+  /*< private >*/
+  char unused;
+} hb_user_data_key_t;
+
+typedef void (*hb_destroy_func_t) (void *user_data);
+
+
 HB_END_DECLS
 
 #endif /* HB_COMMON_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-fallback-shape-private.hh
@@ -0,0 +1,48 @@
+/*
+ * 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_FALLBACK_SHAPE_PRIVATE_HH
+#define HB_FALLBACK_SHAPE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-shape.h"
+
+
+HB_BEGIN_DECLS
+
+
+HB_INTERNAL hb_bool_t
+hb_fallback_shape (hb_font_t          *font,
+		   hb_buffer_t        *buffer,
+		   const hb_feature_t *features,
+		   unsigned int        num_features,
+		   const char * const *shaper_options);
+
+
+HB_END_DECLS
+
+#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
@@ -0,0 +1,62 @@
+/*
+ * 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
+ */
+
+#include "hb-fallback-shape-private.hh"
+
+#include "hb-buffer-private.hh"
+
+hb_bool_t
+hb_fallback_shape (hb_font_t          *font,
+		   hb_buffer_t        *buffer,
+		   const hb_feature_t *features,
+		   unsigned int        num_features,
+		   const char * const *shaper_options)
+{
+  buffer->guess_properties ();
+
+  unsigned int count = buffer->len;
+
+  for (unsigned int i = 0; i < count; i++)
+    hb_font_get_glyph (font, buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
+
+  buffer->clear_positions ();
+
+  for (unsigned int i = 0; i < count; i++) {
+    hb_font_get_glyph_advance_for_direction (font, buffer->info[i].codepoint,
+					     buffer->props.direction,
+					     &buffer->pos[i].x_advance,
+					     &buffer->pos[i].y_advance);
+    hb_font_subtract_glyph_origin_for_direction (font, buffer->info[i].codepoint,
+						 buffer->props.direction,
+						 &buffer->pos[i].x_offset,
+						 &buffer->pos[i].y_offset);
+  }
+
+  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+    hb_buffer_reverse (buffer);
+
+  return TRUE;
+}
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-font-private.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_FONT_PRIVATE_H
-#define HB_FONT_PRIVATE_H
-
-#include "hb-private.h"
-
-#include "hb-font.h"
-
-HB_BEGIN_DECLS
-
-
-/*
- * hb_font_funcs_t
- */
-
-struct _hb_font_funcs_t {
-  hb_reference_count_t ref_count;
-
-  hb_bool_t immutable;
-
-  struct {
-    hb_font_get_glyph_func_t		get_glyph;
-    hb_font_get_glyph_advance_func_t	get_glyph_advance;
-    hb_font_get_glyph_extents_func_t	get_glyph_extents;
-    hb_font_get_contour_point_func_t	get_contour_point;
-    hb_font_get_kerning_func_t		get_kerning;
-  } v;
-};
-
-extern HB_INTERNAL hb_font_funcs_t _hb_font_funcs_nil;
-
-
-/*
- * hb_face_t
- */
-
-struct _hb_face_t {
-  hb_reference_count_t ref_count;
-
-  hb_get_table_func_t  get_table;
-  hb_destroy_func_t    destroy;
-  void                *user_data;
-
-  hb_blob_t *head_blob;
-  const struct head *head_table;
-
-  struct hb_ot_layout_t *ot_layout;
-};
-
-
-/*
- * hb_font_t
- */
-
-struct _hb_font_t {
-  hb_reference_count_t ref_count;
-
-  unsigned int x_scale;
-  unsigned int y_scale;
-
-  unsigned int x_ppem;
-  unsigned int y_ppem;
-
-  hb_font_funcs_t   *klass;
-  hb_destroy_func_t  destroy;
-  void              *user_data;
-};
-
-
-HB_END_DECLS
-
-#endif /* HB_FONT_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -0,0 +1,163 @@
+/*
+ * 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_FONT_PRIVATE_HH
+#define HB_FONT_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-font.h"
+#include "hb-object-private.hh"
+
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
+  HB_FONT_FUNC_IMPLEMENT (glyph) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
+  HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
+  /* ^--- Add new callbacks here */
+
+struct _hb_font_funcs_t {
+  hb_object_header_t header;
+
+  hb_bool_t immutable;
+
+  /* Don't access these directly.  Call hb_font_get_*() instead. */
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } get;
+
+  struct {
+#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+  } user_data;
+
+  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;
+
+  hb_bool_t immutable;
+
+  hb_reference_table_func_t  reference_table;
+  void                      *user_data;
+  hb_destroy_func_t          destroy;
+
+  struct hb_ot_layout_t *ot_layout;
+
+  unsigned int index;
+  unsigned int upem;
+};
+
+
+/*
+ * hb_font_t
+ */
+
+struct _hb_font_t {
+  hb_object_header_t header;
+
+  hb_bool_t immutable;
+
+  hb_font_t *parent;
+  hb_face_t *face;
+
+  int x_scale;
+  int y_scale;
+
+  unsigned int x_ppem;
+  unsigned int y_ppem;
+
+  hb_font_funcs_t   *klass;
+  void              *user_data;
+  hb_destroy_func_t  destroy;
+
+
+  /* Convert from font-space to user-space */
+  inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
+  inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
+
+  /* Convert from parent-font user-space to our user-space */
+  inline hb_position_t parent_scale_x_distance (hb_position_t v) {
+    if (unlikely (parent && parent->x_scale != x_scale))
+      return v * (int64_t) this->x_scale / this->parent->x_scale;
+    return v;
+  }
+  inline hb_position_t parent_scale_y_distance (hb_position_t v) {
+    if (unlikely (parent && parent->y_scale != y_scale))
+      return v * (int64_t) this->y_scale / this->parent->y_scale;
+    return v;
+  }
+  inline hb_position_t parent_scale_x_position (hb_position_t v) {
+    return parent_scale_x_distance (v);
+  }
+  inline hb_position_t parent_scale_y_position (hb_position_t v) {
+    return parent_scale_y_distance (v);
+  }
+
+  inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
+    *x = parent_scale_x_distance (*x);
+    *y = parent_scale_y_distance (*y);
+  }
+  inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
+    *x = parent_scale_x_position (*x);
+    *y = parent_scale_y_position (*y);
+  }
+
+
+  private:
+  inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
+};
+
+
+
+#endif /* HB_FONT_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -19,319 +19,560 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
-#include "hb-private.h"
-
-#include "hb-font-private.h"
-#include "hb-blob-private.h"
-#include "hb-open-file-private.hh"
+#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 <string.h>
 
-HB_BEGIN_DECLS
 
 
 /*
  * hb_font_funcs_t
  */
 
-static hb_codepoint_t
+static hb_bool_t
 hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
-		       hb_face_t *face HB_UNUSED,
-		       const void *user_data HB_UNUSED,
-		       hb_codepoint_t unicode HB_UNUSED,
-		       hb_codepoint_t variation_selector HB_UNUSED)
-{ return 0; }
+		       void *font_data HB_UNUSED,
+		       hb_codepoint_t unicode,
+		       hb_codepoint_t variation_selector,
+		       hb_codepoint_t *glyph,
+		       void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
+
+  *glyph = 0;
+  return FALSE;
+}
+
+static hb_position_t
+hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
+				 void *font_data HB_UNUSED,
+				 hb_codepoint_t glyph,
+				 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
+
+  return font->x_scale;
+}
 
-static void
-hb_font_get_glyph_advance_nil (hb_font_t *font HB_UNUSED,
-			       hb_face_t *face HB_UNUSED,
-			       const void *user_data HB_UNUSED,
-			       hb_codepoint_t glyph HB_UNUSED,
-			       hb_position_t *x_advance HB_UNUSED,
-			       hb_position_t *y_advance HB_UNUSED)
-{ }
+static hb_position_t
+hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
+				 void *font_data HB_UNUSED,
+				 hb_codepoint_t glyph,
+				 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
+
+  return font->y_scale;
+}
 
-static void
-hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
-			       hb_face_t *face HB_UNUSED,
-			       const void *user_data HB_UNUSED,
-			       hb_codepoint_t glyph HB_UNUSED,
-			       hb_glyph_extents_t *extents HB_UNUSED)
-{ }
+static hb_bool_t
+hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
+				void *font_data HB_UNUSED,
+				hb_codepoint_t glyph,
+				hb_position_t *x,
+				hb_position_t *y,
+				void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent,
+						glyph,
+						x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return FALSE;
+}
 
 static hb_bool_t
-hb_font_get_contour_point_nil (hb_font_t *font HB_UNUSED,
-			       hb_face_t *face HB_UNUSED,
-			       const void *user_data HB_UNUSED,
-			       unsigned int point_index HB_UNUSED,
-			       hb_codepoint_t glyph HB_UNUSED,
-			       hb_position_t *x HB_UNUSED,
-			       hb_position_t *y HB_UNUSED)
-{ return false; }
+hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
+				void *font_data HB_UNUSED,
+				hb_codepoint_t glyph,
+				hb_position_t *x,
+				hb_position_t *y,
+				void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent,
+						glyph,
+						x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return FALSE;
+}
+
+static hb_position_t
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
+				 void *font_data HB_UNUSED,
+				 hb_codepoint_t left_glyph,
+				 hb_codepoint_t right_glyph,
+				 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
+
+  return 0;
+}
 
 static hb_position_t
-hb_font_get_kerning_nil (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data HB_UNUSED,
-			 hb_codepoint_t first_glyph HB_UNUSED,
-			 hb_codepoint_t second_glyph HB_UNUSED)
-{ return 0; }
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
+				 void *font_data HB_UNUSED,
+				 hb_codepoint_t top_glyph,
+				 hb_codepoint_t bottom_glyph,
+				 void *user_data HB_UNUSED)
+{
+  if (font->parent)
+    return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
+
+  return 0;
+}
+
+static hb_bool_t
+hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
+			       void *font_data HB_UNUSED,
+			       hb_codepoint_t glyph,
+			       hb_glyph_extents_t *extents,
+			       void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
+					       glyph,
+					       extents);
+    if (ret) {
+      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+      font->parent_scale_distance (&extents->width, &extents->height);
+    }
+    return ret;
+  }
 
-hb_font_funcs_t _hb_font_funcs_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  TRUE,  /* immutable */
+  memset (extents, 0, sizeof (*extents));
+  return FALSE;
+}
+
+static hb_bool_t
+hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
+				     void *font_data HB_UNUSED,
+				     hb_codepoint_t glyph,
+				     unsigned int point_index,
+				     hb_position_t *x,
+				     hb_position_t *y,
+				     void *user_data HB_UNUSED)
+{
+  if (font->parent) {
+    hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent,
+						     glyph, point_index,
+						     x, y);
+    if (ret)
+      font->parent_scale_position (x, y);
+    return ret;
+  }
+
+  *x = *y = 0;
+  return FALSE;
+}
+
+
+static hb_font_funcs_t _hb_font_funcs_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  TRUE, /* immutable */
+
   {
-    hb_font_get_glyph_nil,
-    hb_font_get_glyph_advance_nil,
-    hb_font_get_glyph_extents_nil,
-    hb_font_get_contour_point_nil,
-    hb_font_get_kerning_nil
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
   }
 };
 
+
 hb_font_funcs_t *
 hb_font_funcs_create (void)
 {
   hb_font_funcs_t *ffuncs;
 
-  if (!HB_OBJECT_DO_CREATE (hb_font_funcs_t, ffuncs))
+  if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
     return &_hb_font_funcs_nil;
 
-  ffuncs->v = _hb_font_funcs_nil.v;
+  ffuncs->get = _hb_font_funcs_nil.get;
 
   return ffuncs;
 }
 
 hb_font_funcs_t *
-hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
+hb_font_funcs_get_empty (void)
 {
-  HB_OBJECT_DO_REFERENCE (ffuncs);
+  return &_hb_font_funcs_nil;
 }
 
-unsigned int
-hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs)
+hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
 {
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (ffuncs);
+  return hb_object_reference (ffuncs);
 }
 
 void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
 {
-  HB_OBJECT_DO_DESTROY (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_t *
-hb_font_funcs_copy (hb_font_funcs_t *other_ffuncs)
+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)
 {
-  hb_font_funcs_t *ffuncs;
+  return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
+}
 
-  if (!HB_OBJECT_DO_CREATE (hb_font_funcs_t, ffuncs))
-    return &_hb_font_funcs_nil;
+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);
+}
 
-  ffuncs->v = other_ffuncs->v;
-
-  return ffuncs;
-}
 
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
 {
-  if (HB_OBJECT_IS_INERT (ffuncs))
+  if (hb_object_is_inert (ffuncs))
     return;
 
   ffuncs->immutable = TRUE;
 }
 
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
 {
   return ffuncs->immutable;
 }
 
 
-void
-hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
-			      hb_font_get_glyph_func_t glyph_func)
-{
-  if (ffuncs->immutable)
-    return;
-
-  ffuncs->v.get_glyph = glyph_func ? glyph_func : hb_font_get_glyph_nil;
+#define HB_FONT_FUNC_IMPLEMENT(name) \
+                                                                         \
+void                                                                     \
+hb_font_funcs_set_##name##_func (hb_font_funcs_t             *ffuncs,    \
+                                 hb_font_get_##name##_func_t  func,      \
+                                 void                        *user_data, \
+                                 hb_destroy_func_t            destroy)   \
+{                                                                        \
+  if (ffuncs->immutable) {                                               \
+    if (destroy)                                                         \
+      destroy (user_data);                                               \
+    return;                                                              \
+  }                                                                      \
+                                                                         \
+  if (ffuncs->destroy.name)                                              \
+    ffuncs->destroy.name (ffuncs->user_data.name);                       \
+                                                                         \
+  if (func) {                                                            \
+    ffuncs->get.name = func;                                             \
+    ffuncs->user_data.name = user_data;                                  \
+    ffuncs->destroy.name = destroy;                                      \
+  } else {                                                               \
+    ffuncs->get.name = hb_font_get_##name##_nil;                         \
+    ffuncs->user_data.name = NULL;                                       \
+    ffuncs->destroy.name = NULL;                                         \
+  }                                                                      \
 }
 
-void
-hb_font_funcs_set_glyph_advance_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_advance_func_t glyph_advance_func)
+HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+
+hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+		   hb_codepoint_t *glyph)
 {
-  if (ffuncs->immutable)
-    return;
+  *glyph = 0;
+  return font->klass->get.glyph (font, font->user_data,
+				 unicode, variation_selector, glyph,
+				 font->klass->user_data.glyph);
+}
 
-  ffuncs->v.get_glyph_advance = glyph_advance_func ? glyph_advance_func : hb_font_get_glyph_advance_nil;
+hb_position_t
+hb_font_get_glyph_h_advance (hb_font_t *font,
+			     hb_codepoint_t glyph)
+{
+  return font->klass->get.glyph_h_advance (font, font->user_data,
+					   glyph,
+					   font->klass->user_data.glyph_h_advance);
+}
+
+hb_position_t
+hb_font_get_glyph_v_advance (hb_font_t *font,
+			     hb_codepoint_t glyph)
+{
+  return font->klass->get.glyph_v_advance (font, font->user_data,
+					   glyph,
+					   font->klass->user_data.glyph_v_advance);
 }
 
-void
-hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_extents_func_t glyph_extents_func)
+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)
 {
-  if (ffuncs->immutable)
-    return;
+  *x = *y = 0;
+  return font->klass->get.glyph_h_origin (font, font->user_data,
+					   glyph, x, y,
+					   font->klass->user_data.glyph_h_origin);
+}
 
-  ffuncs->v.get_glyph_extents = glyph_extents_func ? glyph_extents_func : hb_font_get_glyph_extents_nil;
+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)
+{
+  *x = *y = 0;
+  return font->klass->get.glyph_v_origin (font, font->user_data,
+					   glyph, x, y,
+					   font->klass->user_data.glyph_v_origin);
+}
+
+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->klass->get.glyph_h_kerning (font, font->user_data,
+					   left_glyph, right_glyph,
+					   font->klass->user_data.glyph_h_kerning);
 }
 
-void
-hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_contour_point_func_t contour_point_func)
+hb_position_t
+hb_font_get_glyph_v_kerning (hb_font_t *font,
+			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 {
-  if (ffuncs->immutable)
-    return;
-
-  ffuncs->v.get_contour_point = contour_point_func ? contour_point_func : hb_font_get_contour_point_nil;
+  return font->klass->get.glyph_v_kerning (font, font->user_data,
+				     left_glyph, right_glyph,
+				     font->klass->user_data.glyph_v_kerning);
 }
 
-void
-hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
-				hb_font_get_kerning_func_t kerning_func)
+hb_bool_t
+hb_font_get_glyph_extents (hb_font_t *font,
+			   hb_codepoint_t glyph,
+			   hb_glyph_extents_t *extents)
 {
-  if (ffuncs->immutable)
-    return;
+  memset (extents, 0, sizeof (*extents));
+  return font->klass->get.glyph_extents (font, font->user_data,
+					 glyph,
+					 extents,
+					 font->klass->user_data.glyph_extents);
+}
 
-  ffuncs->v.get_kerning = kerning_func ? kerning_func : hb_font_get_kerning_nil;
+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)
+{
+  *x = *y = 0;
+  return font->klass->get.glyph_contour_point (font, font->user_data,
+					       glyph, point_index,
+					       x, y,
+					       font->klass->user_data.glyph_contour_point);
 }
 
 
-hb_font_get_glyph_func_t
-hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs)
+/* A bit higher-level, and with fallback */
+
+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 ffuncs->v.get_glyph;
-}
-
-hb_font_get_glyph_advance_func_t
-hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs)
-{
-  return ffuncs->v.get_glyph_advance;
+  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+    *x = hb_font_get_glyph_h_advance (font, glyph);
+    *y = 0;
+  } else {
+    *x = 0;
+    *y = hb_font_get_glyph_v_advance (font, glyph);
+  }
 }
 
-hb_font_get_glyph_extents_func_t
-hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs)
+static void
+guess_v_origin_minus_h_origin (hb_font_t *font,
+			       hb_codepoint_t glyph,
+			       hb_position_t *x, hb_position_t *y)
 {
-  return ffuncs->v.get_glyph_extents;
-}
+  *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
 
-hb_font_get_contour_point_func_t
-hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs)
-{
-  return ffuncs->v.get_contour_point;
-}
-
-hb_font_get_kerning_func_t
-hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs)
-{
-  return ffuncs->v.get_kerning;
+  /* TODO use font_metics.ascent */
+  *y = font->y_scale;
 }
 
 
-
-hb_codepoint_t
-hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
-		   hb_codepoint_t unicode, hb_codepoint_t variation_selector)
+void
+hb_font_get_glyph_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->klass->v.get_glyph (font, face, font->user_data,
-				   unicode, variation_selector);
+  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+    hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
+    if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
+      hb_position_t dx, dy;
+      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
+      *x -= dx; *y -= dy;
+    }
+  } else {
+    hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
+    if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
+      hb_position_t dx, dy;
+      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
+      *x += dx; *y += dy;
+    }
+  }
 }
 
 void
-hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph,
-			   hb_position_t *x_advance, hb_position_t *y_advance)
+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)
 {
-  *x_advance = *y_advance = 0;
-  return font->klass->v.get_glyph_advance (font, face, font->user_data,
-					   glyph, x_advance, y_advance);
+  hb_position_t origin_x, origin_y;
+
+  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
+
+  *x += origin_x;
+  *y += origin_y;
 }
 
 void
-hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph, hb_glyph_extents_t *extents)
+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)
 {
-  memset (extents, 0, sizeof (*extents));
-  return font->klass->v.get_glyph_extents (font, face, font->user_data,
-					   glyph, extents);
+  hb_position_t origin_x, origin_y;
+
+  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
+
+  *x -= origin_x;
+  *y -= origin_y;
+}
+
+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)
+{
+  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+    *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
+    *y = 0;
+  } else {
+    *x = 0;
+    *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
+  }
 }
 
 hb_bool_t
-hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
-			   unsigned int point_index,
-			   hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
+hb_font_get_glyph_extents_for_origin (hb_font_t *font,
+				      hb_codepoint_t glyph,
+				      hb_direction_t direction,
+				      hb_glyph_extents_t *extents)
 {
-  *x = 0; *y = 0;
-  return font->klass->v.get_contour_point (font, face, font->user_data,
-					   point_index,
-					   glyph, x, y);
+  hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
+
+  if (ret)
+    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
+
+  return ret;
 }
 
-hb_position_t
-hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
-		     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph)
+hb_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->klass->v.get_kerning (font, face, font->user_data,
-				     first_glyph, second_glyph);
+  hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
+
+  if (ret)
+    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
+
+  return ret;
 }
 
 
 /*
  * hb_face_t
  */
 
 static hb_face_t _hb_face_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  HB_OBJECT_HEADER_STATIC,
 
-  NULL, /* get_table */
-  NULL, /* destroy */
+  TRUE, /* immutable */
+
+  NULL, /* reference_table */
   NULL, /* user_data */
+  NULL, /* destroy */
 
-  NULL, /* head_blob */
-  NULL, /* head_table */
+  NULL, /* ot_layout */
 
-  NULL  /* ot_layout */
+  0,    /* index */
+  1000  /* upem */
 };
 
 
 hb_face_t *
-hb_face_create_for_tables (hb_get_table_func_t  get_table,
-			   hb_destroy_func_t    destroy,
-			   void                *user_data)
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
+			   void                      *user_data,
+			   hb_destroy_func_t          destroy)
 {
   hb_face_t *face;
 
-  if (!HB_OBJECT_DO_CREATE (hb_face_t, face)) {
+  if (!reference_table || !(face = hb_object_create<hb_face_t> ())) {
     if (destroy)
       destroy (user_data);
     return &_hb_face_nil;
   }
 
-  face->get_table = get_table;
+  face->reference_table = reference_table;
+  face->user_data = user_data;
   face->destroy = destroy;
-  face->user_data = user_data;
 
-  face->ot_layout = _hb_ot_layout_new (face);
+  face->ot_layout = _hb_ot_layout_create (face);
 
-  face->head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
-  face->head_table = Sanitizer<head>::lock_instance (face->head_blob);
+  face->upem = 0;
 
   return face;
 }
 
 
 typedef struct _hb_face_for_data_closure_t {
   hb_blob_t *blob;
   unsigned int  index;
@@ -355,229 +596,393 @@ static hb_face_for_data_closure_t *
 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_get_table (hb_tag_t tag, void *user_data)
+_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 OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
   const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
 
   const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
 
   hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
 
-  hb_blob_unlock (data->blob);
-
   return blob;
 }
 
 hb_face_t *
-hb_face_create_for_data (hb_blob_t    *blob,
-			 unsigned int  index)
+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_nil;
+
   hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
 
   if (unlikely (!closure))
     return &_hb_face_nil;
 
-  return hb_face_create_for_tables (_hb_face_for_data_get_table,
-				    (hb_destroy_func_t) _hb_face_for_data_closure_destroy,
-				    closure);
+  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 &_hb_face_nil;
 }
 
 
 hb_face_t *
 hb_face_reference (hb_face_t *face)
 {
-  HB_OBJECT_DO_REFERENCE (face);
-}
-
-unsigned int
-hb_face_get_reference_count (hb_face_t *face)
-{
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (face);
+  return hb_object_reference (face);
 }
 
 void
 hb_face_destroy (hb_face_t *face)
 {
-  HB_OBJECT_DO_DESTROY (face);
+  if (!hb_object_destroy (face)) return;
 
-  _hb_ot_layout_free (face->ot_layout);
-
-  hb_blob_unlock (face->head_blob);
-  hb_blob_destroy (face->head_blob);
+  _hb_ot_layout_destroy (face->ot_layout);
 
   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_get_table (hb_face_t *face,
-		   hb_tag_t   tag)
+hb_face_reference_table (hb_face_t *face,
+			 hb_tag_t   tag)
 {
   hb_blob_t *blob;
 
-  if (unlikely (!face || !face->get_table))
-    return &_hb_blob_nil;
+  if (unlikely (!face || !face->reference_table))
+    return hb_blob_get_empty ();
 
-  blob = face->get_table (tag, face->user_data);
+  blob = face->reference_table (face, tag, face->user_data);
+  if (unlikely (!blob))
+    return hb_blob_get_empty ();
 
   return blob;
 }
 
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face)
+{
+  return hb_face_reference_table (face, HB_TAG_NONE);
+}
+
+void
+hb_face_set_index (hb_face_t    *face,
+		   unsigned int  index)
+{
+  if (hb_object_is_inert (face))
+    return;
+
+  face->index = 0;
+}
+
+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->head_table ? face->head_table : &Null(head))->get_upem ();
+  if (unlikely (!face->upem)) {
+    hb_blob_t *head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head));
+    const head *head_table = Sanitizer<head>::lock_instance (head_blob);
+    face->upem = head_table->get_upem ();
+    hb_blob_destroy (head_blob);
+  }
+  return face->upem;
 }
 
 
 /*
  * hb_font_t
  */
 
 static hb_font_t _hb_font_nil = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
+  HB_OBJECT_HEADER_STATIC,
+
+  TRUE, /* immutable */
+
+  NULL, /* parent */
+  &_hb_face_nil,
 
   0, /* x_scale */
   0, /* y_scale */
 
   0, /* x_ppem */
   0, /* y_ppem */
 
-  NULL, /* klass */
-  NULL, /* destroy */
-  NULL  /* user_data */
+  &_hb_font_funcs_nil, /* klass */
+  NULL, /* user_data */
+  NULL  /* destroy */
 };
 
 hb_font_t *
-hb_font_create (void)
+hb_font_create (hb_face_t *face)
 {
   hb_font_t *font;
 
-  if (!HB_OBJECT_DO_CREATE (hb_font_t, font))
+  if (unlikely (!face))
+    face = &_hb_face_nil;
+  if (unlikely (hb_object_is_inert (face)))
+    return &_hb_font_nil;
+  if (!(font = hb_object_create<hb_font_t> ()))
     return &_hb_font_nil;
 
+  hb_face_make_immutable (face);
+  font->face = hb_face_reference (face);
+  font->klass = &_hb_font_funcs_nil;
+
+  return font;
+}
+
+hb_font_t *
+hb_font_create_sub_font (hb_font_t *parent)
+{
+  if (unlikely (!parent))
+    return &_hb_font_nil;
+
+  hb_font_t *font = hb_font_create (parent->face);
+
+  if (unlikely (hb_object_is_inert (font)))
+    return font;
+
+  hb_font_make_immutable (parent);
+  font->parent = hb_font_reference (parent);
+
+  font->x_scale = parent->x_scale;
+  font->y_scale = parent->y_scale;
+  font->x_ppem = parent->x_ppem;
+  font->y_ppem = parent->y_ppem;
+
   font->klass = &_hb_font_funcs_nil;
 
   return font;
 }
 
 hb_font_t *
-hb_font_reference (hb_font_t *font)
+hb_font_get_empty (void)
 {
-  HB_OBJECT_DO_REFERENCE (font);
+  return &_hb_font_nil;
 }
 
-unsigned int
-hb_font_get_reference_count (hb_font_t *font)
+hb_font_t *
+hb_font_reference (hb_font_t *font)
 {
-  HB_OBJECT_DO_GET_REFERENCE_COUNT (font);
+  return hb_object_reference (font);
 }
 
 void
 hb_font_destroy (hb_font_t *font)
 {
-  HB_OBJECT_DO_DESTROY (font);
+  if (!hb_object_destroy (font)) return;
 
+  hb_font_destroy (font->parent);
+  hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
   if (font->destroy)
     font->destroy (font->user_data);
 
   free (font);
 }
 
+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);
+}
+
+void *
+hb_font_get_user_data (hb_font_t          *font,
+		       hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (font, key);
+}
+
+void
+hb_font_make_immutable (hb_font_t *font)
+{
+  if (hb_object_is_inert (font))
+    return;
+
+  font->immutable = true;
+}
+
+hb_bool_t
+hb_font_is_immutable (hb_font_t *font)
+{
+  return font->immutable;
+}
+
+hb_font_t *
+hb_font_get_parent (hb_font_t *font)
+{
+  return font->parent;
+}
+
+hb_face_t *
+hb_font_get_face (hb_font_t *font)
+{
+  return font->face;
+}
+
+
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
-		   hb_destroy_func_t  destroy,
-		   void              *user_data)
+		   void              *user_data,
+		   hb_destroy_func_t  destroy)
 {
-  if (HB_OBJECT_IS_INERT (font))
+  if (font->immutable) {
+    if (destroy)
+      destroy (user_data);
     return;
+  }
 
   if (font->destroy)
     font->destroy (font->user_data);
 
   if (!klass)
     klass = &_hb_font_funcs_nil;
 
   hb_font_funcs_reference (klass);
   hb_font_funcs_destroy (font->klass);
   font->klass = klass;
+  font->user_data = user_data;
   font->destroy = destroy;
-  font->user_data = user_data;
 }
 
 void
-hb_font_unset_funcs (hb_font_t          *font,
-		     hb_font_funcs_t   **klass,
-		     hb_destroy_func_t  *destroy,
-		     void              **user_data)
+hb_font_set_funcs_data (hb_font_t         *font,
+		        void              *user_data,
+		        hb_destroy_func_t  destroy)
 {
-  /* None of the input arguments can be NULL. */
+  /* Destroy user_data? */
+  if (font->immutable) {
+    if (destroy)
+      destroy (user_data);
+    return;
+  }
 
-  *klass = font->klass;
-  *destroy = font->destroy;
-  *user_data = font->user_data;
+  if (font->destroy)
+    font->destroy (font->user_data);
 
-  if (HB_OBJECT_IS_INERT (font))
-    return;
+  font->user_data = user_data;
+  font->destroy = destroy;
+}
 
-  font->klass = NULL;
-  font->destroy = NULL;
-  font->user_data = NULL;
-}
 
 void
 hb_font_set_scale (hb_font_t *font,
-		   unsigned int x_scale,
-		   unsigned int y_scale)
+		   int x_scale,
+		   int y_scale)
 {
-  if (HB_OBJECT_IS_INERT (font))
+  if (font->immutable)
     return;
 
   font->x_scale = x_scale;
   font->y_scale = y_scale;
 }
 
 void
 hb_font_get_scale (hb_font_t *font,
-		   unsigned int *x_scale,
-		   unsigned int *y_scale)
+		   int *x_scale,
+		   int *y_scale)
 {
   if (x_scale) *x_scale = font->x_scale;
   if (y_scale) *y_scale = font->y_scale;
 }
 
 void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem)
 {
-  if (HB_OBJECT_IS_INERT (font))
+  if (font->immutable)
     return;
 
   font->x_ppem = x_ppem;
   font->y_ppem = y_ppem;
 }
 
 void
 hb_font_get_ppem (hb_font_t *font,
 		  unsigned int *x_ppem,
 		  unsigned int *y_ppem)
 {
   if (x_ppem) *x_ppem = font->x_ppem;
   if (y_ppem) *y_ppem = font->y_ppem;
 }
 
 
-HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -36,225 +36,358 @@ 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_for_data (hb_blob_t    *blob,
-			 unsigned int  index);
+hb_face_create (hb_blob_t    *blob,
+		unsigned int  index);
 
-typedef hb_blob_t * (*hb_get_table_func_t)  (hb_tag_t tag, void *user_data);
+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_get_table_func_t  get_table,
-			   hb_destroy_func_t    destroy,
-			   void                *user_data);
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
+			   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);
 
-unsigned int
-hb_face_get_reference_count (hb_face_t *face);
-
 void
 hb_face_destroy (hb_face_t *face);
 
-/* XXX
- *
- * I have two major concerns about this API as it is right now:
- *
- *   - Jonathan Kew convinced me to make it return NULL if table not found (280af1bd),
- *     however, that is WRONG IMO.  The API should not differentiate between a non-existing
- *     table vs a zero-length table vs a very short table.  It only leads to implementations
- *     that check for non-NULL and assume that they've got a usable table going on...  This
- *     actually happened with Firefox.
- *
- *   - It has to be renamed to reference_table() since unlike any other _get_ API, a reference
- *     ownership transfer happens and the user is responsible to destroy the result.
- */
+hb_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_get_table (hb_face_t *face,
-		   hb_tag_t   tag);
+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);
 
 
 /*
  * hb_font_funcs_t
  */
 
 typedef struct _hb_font_funcs_t hb_font_funcs_t;
 
 hb_font_funcs_t *
 hb_font_funcs_create (void);
 
 hb_font_funcs_t *
-hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
+hb_font_funcs_get_empty (void);
 
-unsigned int
-hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs);
+hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
 
 void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
 
-hb_font_funcs_t *
-hb_font_funcs_copy (hb_font_funcs_t *ffuncs);
+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);
+
+
+void *
+hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
+			     hb_user_data_key_t *key);
+
 
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
 
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
 /* funcs */
 
 typedef struct _hb_glyph_extents_t
 {
-    hb_position_t x_bearing;
-    hb_position_t y_bearing;
-    hb_position_t width;
-    hb_position_t height;
+  hb_position_t x_bearing;
+  hb_position_t y_bearing;
+  hb_position_t width;
+  hb_position_t height;
 } hb_glyph_extents_t;
 
-typedef hb_codepoint_t (*hb_font_get_glyph_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						    hb_codepoint_t unicode, hb_codepoint_t variation_selector);
-typedef void (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						  hb_codepoint_t glyph,
-						  hb_position_t *x_advance, hb_position_t *y_advance);
-typedef void (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						  hb_codepoint_t glyph,
-						  hb_glyph_extents_t *metrics);
-typedef hb_bool_t (*hb_font_get_contour_point_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						       unsigned int point_index, hb_codepoint_t glyph,
-						       hb_position_t *x, hb_position_t *y);
-typedef hb_position_t (*hb_font_get_kerning_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
-						     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
+
+/* func types */
+
+typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
+					       hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+					       hb_codepoint_t *glyph,
+					       void *user_data);
+
+
+typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
+							   hb_codepoint_t glyph,
+							   void *user_data);
+typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
+typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
 
+typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
+						      hb_codepoint_t glyph,
+						      hb_position_t *x, hb_position_t *y,
+						      void *user_data);
+typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
+typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
+
+typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
+							   hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+							   void *user_data);
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
+
+
+typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
+						       hb_codepoint_t glyph,
+						       hb_glyph_extents_t *extents,
+						       void *user_data);
+typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
+							     hb_codepoint_t glyph, unsigned int point_index,
+							     hb_position_t *x, hb_position_t *y,
+							     void *user_data);
+
+
+/* func setters */
 
 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 glyph_func,
+			      void *user_data, hb_destroy_func_t destroy);
+
+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);
+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);
 
 void
-hb_font_funcs_set_glyph_advance_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_advance_func_t glyph_advance_func);
+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);
+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);
+
+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);
+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);
 
 void
 hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_glyph_extents_func_t glyph_extents_func);
-
+				      hb_font_get_glyph_extents_func_t func,
+				      void *user_data, hb_destroy_func_t destroy);
 void
-hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
-				      hb_font_get_contour_point_func_t contour_point_func);
-
-void
-hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
-				hb_font_get_kerning_func_t kerning_func);
+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);
 
 
-/* These never return NULL.  Return fallback defaults instead. */
+/* func dispatch */
+
+hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+		   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+		   hb_codepoint_t *glyph);
 
-hb_font_get_glyph_func_t
-hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs);
-
-hb_font_get_glyph_advance_func_t
-hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs);
+hb_position_t
+hb_font_get_glyph_h_advance (hb_font_t *font,
+			     hb_codepoint_t glyph);
+hb_position_t
+hb_font_get_glyph_v_advance (hb_font_t *font,
+			     hb_codepoint_t glyph);
 
-hb_font_get_glyph_extents_func_t
-hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs);
+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);
+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);
 
-hb_font_get_contour_point_func_t
-hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs);
+hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+			     hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+hb_position_t
+hb_font_get_glyph_v_kerning (hb_font_t *font,
+			     hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
 
-hb_font_get_kerning_func_t
-hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs);
+hb_bool_t
+hb_font_get_glyph_extents (hb_font_t *font,
+			   hb_codepoint_t glyph,
+			   hb_glyph_extents_t *extents);
+
+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);
 
 
-hb_codepoint_t
-hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
-		   hb_codepoint_t unicode, hb_codepoint_t variation_selector);
-
-void
-hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph,
-			   hb_position_t *x_advance, hb_position_t *y_advance);
+/* high-level funcs, with fallback */
 
 void
-hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face,
-			   hb_codepoint_t glyph,
-			   hb_glyph_extents_t *metrics);
+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);
+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);
+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);
+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);
+
+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);
 
 hb_bool_t
-hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
-			   unsigned int point_index, hb_codepoint_t glyph,
-			   hb_position_t *x, hb_position_t *y);
+hb_font_get_glyph_extents_for_origin (hb_font_t *font,
+				      hb_codepoint_t glyph,
+				      hb_direction_t direction,
+				      hb_glyph_extents_t *extents);
 
-hb_position_t
-hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
-		     hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
+hb_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);
 
 
 /*
  * hb_font_t
  */
 
 /* Fonts are very light-weight objects */
 
 hb_font_t *
-hb_font_create (void);
+hb_font_create (hb_face_t *face);
+
+hb_font_t *
+hb_font_create_sub_font (hb_font_t *parent);
+
+hb_font_t *
+hb_font_get_empty (void);
 
 hb_font_t *
 hb_font_reference (hb_font_t *font);
 
-unsigned int
-hb_font_get_reference_count (hb_font_t *font);
+void
+hb_font_destroy (hb_font_t *font);
+
+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);
+
+
+void *
+hb_font_get_user_data (hb_font_t          *font,
+		       hb_user_data_key_t *key);
 
 void
-hb_font_destroy (hb_font_t *font);
+hb_font_make_immutable (hb_font_t *font);
+
+hb_bool_t
+hb_font_is_immutable (hb_font_t *font);
+
+hb_font_t *
+hb_font_get_parent (hb_font_t *font);
+
+hb_face_t *
+hb_font_get_face (hb_font_t *font);
+
 
 void
 hb_font_set_funcs (hb_font_t         *font,
 		   hb_font_funcs_t   *klass,
-		   hb_destroy_func_t  destroy,
-		   void              *user_data);
+		   void              *font_data,
+		   hb_destroy_func_t  destroy);
 
-/* Returns what was set and unsets it, but doesn't destroy(user_data).
- * This is useful for wrapping / chaining font_funcs_t's.
- *
- * The client is responsible for:
- *
- *   - Take ownership of the reference on the returned klass,
- *
- *   - Calling "destroy(user_data)" exactly once if returned destroy func
- *     is not NULL and the returned info is not needed anymore.
- */
+/* Be *very* careful with this function! */
 void
-hb_font_unset_funcs (hb_font_t          *font,
-		     hb_font_funcs_t   **klass,
-		     hb_destroy_func_t  *destroy,
-		     void              **user_data);
+hb_font_set_funcs_data (hb_font_t         *font,
+		        void              *font_data,
+		        hb_destroy_func_t  destroy);
 
 
-/*
- * We should add support for full matrices.
- */
 void
 hb_font_set_scale (hb_font_t *font,
-		   unsigned int x_scale,
-		   unsigned int y_scale);
+		   int x_scale,
+		   int y_scale);
 
 void
 hb_font_get_scale (hb_font_t *font,
-		   unsigned int *x_scale,
-		   unsigned int *y_scale);
+		   int *x_scale,
+		   int *y_scale);
 
 /*
  * A zero value means "no hinting in that direction"
  */
 void
 hb_font_set_ppem (hb_font_t *font,
 		  unsigned int x_ppem,
 		  unsigned int y_ppem);
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-ft.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright (C) 2009  Keith Stribley <devel@thanlwinsoft.org>
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-ft.h"
-
-#include "hb-font-private.h"
-
-#include FT_TRUETYPE_TABLES_H
-
-HB_BEGIN_DECLS
-
-
-static hb_codepoint_t
-hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
-		 hb_face_t *face HB_UNUSED,
-		 const void *user_data,
-		 hb_codepoint_t unicode,
-		 hb_codepoint_t variation_selector)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-
-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
-  if (unlikely (variation_selector)) {
-    hb_codepoint_t glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
-    if (glyph)
-      return glyph;
-  }
-#endif
-
-  return FT_Get_Char_Index (ft_face, unicode);
-}
-
-static void
-hb_ft_get_glyph_advance (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data,
-			 hb_codepoint_t glyph,
-			 hb_position_t *x_advance,
-			 hb_position_t *y_advance)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  int load_flags = FT_LOAD_DEFAULT;
-
-  /* TODO: load_flags, embolden, etc */
-
-  if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
-  {
-    *x_advance = ft_face->glyph->advance.x;
-    *y_advance = ft_face->glyph->advance.y;
-  }
-}
-
-static void
-hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data,
-			 hb_codepoint_t glyph,
-			 hb_glyph_extents_t *extents)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  int load_flags = FT_LOAD_DEFAULT;
-
-  /* TODO: load_flags, embolden, etc */
-
-  if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
-  {
-    /* XXX: A few negations should be in order here, not sure. */
-    extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
-    extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
-    extents->width = ft_face->glyph->metrics.width;
-    extents->height = ft_face->glyph->metrics.height;
-  }
-}
-
-static hb_bool_t
-hb_ft_get_contour_point (hb_font_t *font HB_UNUSED,
-			 hb_face_t *face HB_UNUSED,
-			 const void *user_data,
-			 unsigned int point_index,
-			 hb_codepoint_t glyph,
-			 hb_position_t *x,
-			 hb_position_t *y)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  int load_flags = FT_LOAD_DEFAULT;
-
-  /* TODO: load_flags, embolden, etc */
-
-  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
-      return FALSE;
-
-  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
-      return FALSE;
-
-  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
-      return FALSE;
-
-  *x = ft_face->glyph->outline.points[point_index].x;
-  *y = ft_face->glyph->outline.points[point_index].y;
-
-  return TRUE;
-}
-
-static hb_position_t
-hb_ft_get_kerning (hb_font_t *font HB_UNUSED,
-		   hb_face_t *face HB_UNUSED,
-		   const void *user_data,
-		   hb_codepoint_t first_glyph,
-		   hb_codepoint_t second_glyph)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  FT_Vector kerning;
-
-  /* TODO: Kern type? */
-  if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning))
-      return 0;
-
-  return kerning.x;
-}
-
-static hb_font_funcs_t ft_ffuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  TRUE, /* immutable */
-  {
-    hb_ft_get_glyph,
-    hb_ft_get_glyph_advance,
-    hb_ft_get_glyph_extents,
-    hb_ft_get_contour_point,
-    hb_ft_get_kerning
-  }
-};
-
-hb_font_funcs_t *
-hb_ft_get_font_funcs (void)
-{
-  return &ft_ffuncs;
-}
-
-
-static hb_blob_t *
-get_table  (hb_tag_t tag, void *user_data)
-{
-  FT_Face ft_face = (FT_Face) user_data;
-  FT_Byte *buffer;
-  FT_ULong  length = 0;
-  FT_Error error;
-
-  if (unlikely (tag == HB_TAG_NONE))
-    return NULL;
-
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
-  if (error)
-    return NULL;
-
-  /* TODO Use FT_Memory? */
-  buffer = (FT_Byte *) malloc (length);
-  if (buffer == NULL)
-    return NULL;
-
-  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
-  if (error)
-    return NULL;
-
-  return hb_blob_create ((const char *) buffer, length,
-			 HB_MEMORY_MODE_WRITABLE,
-			 free, buffer);
-}
-
-
-hb_face_t *
-hb_ft_face_create (FT_Face           ft_face,
-		   hb_destroy_func_t destroy)
-{
-  hb_face_t *face;
-
-  if (ft_face->stream->read == NULL) {
-    hb_blob_t *blob;
-
-    blob = hb_blob_create ((const char *) ft_face->stream->base,
-			   (unsigned int) ft_face->stream->size,
-			   /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */
-			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
-			   destroy, ft_face);
-    face = hb_face_create_for_data (blob, ft_face->face_index);
-    hb_blob_destroy (blob);
-  } else {
-    face = hb_face_create_for_tables (get_table, destroy, ft_face);
-  }
-
-  return face;
-}
-
-static void
-hb_ft_face_finalize (FT_Face ft_face)
-{
-  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
-}
-
-hb_face_t *
-hb_ft_face_create_cached (FT_Face ft_face)
-{
-  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
-  {
-    if (ft_face->generic.finalizer)
-      ft_face->generic.finalizer (ft_face);
-
-    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
-    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
-  }
-
-  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
-}
-
-
-hb_font_t *
-hb_ft_font_create (FT_Face           ft_face,
-		   hb_destroy_func_t destroy)
-{
-  hb_font_t *font;
-
-  font = hb_font_create ();
-  hb_font_set_funcs (font,
-		     hb_ft_get_font_funcs (),
-		     destroy, ft_face);
-  hb_font_set_scale (font,
-		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
-		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
-  hb_font_set_ppem (font,
-		    ft_face->size->metrics.x_ppem,
-		    ft_face->size->metrics.y_ppem);
-
-  return font;
-}
-
-
-HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -0,0 +1,439 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2009  Keith Stribley
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ft.h"
+
+#include "hb-font-private.hh"
+
+#include FT_ADVANCES_H
+#include FT_TRUETYPE_TABLES_H
+
+
+
+#ifndef HB_DEBUG_FT
+#define HB_DEBUG_FT (HB_DEBUG+0)
+#endif
+
+
+/* TODO:
+ *
+ * In general, this file does a fine job of what it's supposed to do.
+ * There are, however, things that need more work:
+ *
+ *   - We don't handle any load_flags.  That definitely has API implications. :(
+ *     I believe hb_ft_font_create() should take load_flags input.
+ *     In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
+ *     buggy.
+ *
+ *   - We don't handle / allow for emboldening / obliqueing.
+ *
+ *   - Rounding, etc?
+ *
+ *   - In the future, we should add constructors to create fonts in font space.
+ *
+ *   - I believe transforms are not correctly implemented.  FreeType does not
+ *     provide any API to get to the transform/delta set on the face. :(
+ *
+ *   - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH?
+ */
+
+
+static hb_bool_t
+hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
+		 void *font_data,
+		 hb_codepoint_t unicode,
+		 hb_codepoint_t variation_selector,
+		 hb_codepoint_t *glyph,
+		 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;
+  }
+#endif
+
+  *glyph = FT_Get_Char_Index (ft_face, unicode);
+  return *glyph != 0;
+}
+
+static hb_position_t
+hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t glyph,
+			   void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+  FT_Fixed v;
+
+  if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
+    return 0;
+
+  return v >> 10;
+}
+
+static hb_position_t
+hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t glyph,
+			   void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT;
+  FT_Fixed v;
+
+  if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
+    return 0;
+
+  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+   * have a Y growing upward.  Hence the extra negation. */
+  return -v >> 10;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data HB_UNUSED,
+			  hb_codepoint_t glyph HB_UNUSED,
+			  hb_position_t *x HB_UNUSED,
+			  hb_position_t *y HB_UNUSED,
+			  void *user_data HB_UNUSED)
+{
+  /* We always work in the horizontal coordinates. */
+  return TRUE;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+			  void *font_data,
+			  hb_codepoint_t glyph,
+			  hb_position_t *x,
+			  hb_position_t *y,
+			  void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+    return FALSE;
+
+  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+   * have a Y growing upward.  Hence the extra negation. */
+  *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
+  *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
+
+  return TRUE;
+}
+
+static hb_position_t
+hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED,
+			   void *font_data,
+			   hb_codepoint_t left_glyph,
+			   hb_codepoint_t right_glyph,
+			   void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  FT_Vector kerningv;
+
+  if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerningv))
+    return 0;
+
+  return kerningv.x;
+}
+
+static hb_position_t
+hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+			   void *font_data HB_UNUSED,
+			   hb_codepoint_t top_glyph HB_UNUSED,
+			   hb_codepoint_t bottom_glyph HB_UNUSED,
+			   void *user_data HB_UNUSED)
+{
+  /* FreeType API doesn't support vertical kerning */
+  return 0;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
+			 void *font_data,
+			 hb_codepoint_t glyph,
+			 hb_glyph_extents_t *extents,
+			 void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+    return FALSE;
+
+  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
+  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
+  extents->width = ft_face->glyph->metrics.width;
+  extents->height = ft_face->glyph->metrics.height;
+  return TRUE;
+}
+
+static hb_bool_t
+hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+			       void *font_data,
+			       hb_codepoint_t glyph,
+			       unsigned int point_index,
+			       hb_position_t *x,
+			       hb_position_t *y,
+			       void *user_data HB_UNUSED)
+{
+  FT_Face ft_face = (FT_Face) font_data;
+  int load_flags = FT_LOAD_DEFAULT;
+
+  if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
+      return FALSE;
+
+  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
+      return FALSE;
+
+  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
+      return FALSE;
+
+  *x = ft_face->glyph->outline.points[point_index].x;
+  *y = ft_face->glyph->outline.points[point_index].y;
+
+  return TRUE;
+}
+
+static hb_font_funcs_t ft_ffuncs = {
+  HB_OBJECT_HEADER_STATIC,
+
+  TRUE, /* immutable */
+
+  {
+    hb_ft_get_glyph,
+    hb_ft_get_glyph_h_advance,
+    hb_ft_get_glyph_v_advance,
+    hb_ft_get_glyph_h_origin,
+    hb_ft_get_glyph_v_origin,
+    hb_ft_get_glyph_h_kerning,
+    hb_ft_get_glyph_v_kerning,
+    hb_ft_get_glyph_extents,
+    hb_ft_get_glyph_contour_point,
+  }
+};
+
+static hb_font_funcs_t *
+_hb_ft_get_font_funcs (void)
+{
+  return &ft_ffuncs;
+}
+
+
+static hb_blob_t *
+reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  FT_Face ft_face = (FT_Face) user_data;
+  FT_Byte *buffer;
+  FT_ULong  length = 0;
+  FT_Error error;
+
+  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+  if (error)
+    return NULL;
+
+  buffer = (FT_Byte *) malloc (length);
+  if (buffer == NULL)
+    return NULL;
+
+  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
+  if (error)
+    return NULL;
+
+  return hb_blob_create ((const char *) buffer, length,
+			 HB_MEMORY_MODE_WRITABLE,
+			 buffer, free);
+}
+
+
+hb_face_t *
+hb_ft_face_create (FT_Face           ft_face,
+		   hb_destroy_func_t destroy)
+{
+  hb_face_t *face;
+
+  if (ft_face->stream->read == NULL) {
+    hb_blob_t *blob;
+
+    blob = hb_blob_create ((const char *) ft_face->stream->base,
+			   (unsigned int) ft_face->stream->size,
+			   /* TODO: We assume that it's mmap()'ed, but FreeType code
+			    * suggests that there are cases we reach here but font is
+			    * not mmapped.  For example, when mmap() fails.  No idea
+			    * how to deal with it better here. */
+			   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+			   ft_face, destroy);
+    face = hb_face_create (blob, ft_face->face_index);
+    hb_blob_destroy (blob);
+  } else {
+    face = hb_face_create_for_tables (reference_table, ft_face, destroy);
+  }
+
+  hb_face_set_index (face, ft_face->face_index);
+  hb_face_set_upem (face, ft_face->units_per_EM);
+
+  return face;
+}
+
+static void
+hb_ft_face_finalize (FT_Face ft_face)
+{
+  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
+}
+
+hb_face_t *
+hb_ft_face_create_cached (FT_Face ft_face)
+{
+  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+  {
+    if (ft_face->generic.finalizer)
+      ft_face->generic.finalizer (ft_face);
+
+    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
+    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
+  }
+
+  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
+}
+
+static void
+_do_nothing (void)
+{
+}
+
+
+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);
+  font = hb_font_create (face);
+  hb_face_destroy (face);
+  hb_font_set_funcs (font,
+		     _hb_ft_get_font_funcs (),
+		     ft_face, (hb_destroy_func_t) _do_nothing);
+  hb_font_set_scale (font,
+		     ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
+		     ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+  hb_font_set_ppem (font,
+		    ft_face->size->metrics.x_ppem,
+		    ft_face->size->metrics.y_ppem);
+
+  return font;
+}
+
+
+
+
+static FT_Library ft_library;
+static hb_bool_t ft_library_initialized;
+static struct ft_library_destructor {
+  ~ft_library_destructor (void) {
+    if (ft_library)
+      FT_Done_FreeType (ft_library);
+  }
+} static_ft_library_destructor;
+
+static FT_Library
+_get_ft_library (void)
+{
+  if (unlikely (!ft_library_initialized)) {
+    FT_Init_FreeType (&ft_library);
+    ft_library_initialized = TRUE;
+  }
+
+  return ft_library;
+}
+
+static void
+_release_blob (FT_Face ft_face)
+{
+  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
+}
+
+void
+hb_ft_font_set_funcs (hb_font_t *font)
+{
+  hb_blob_t *blob = hb_face_reference_blob (font->face);
+  unsigned int blob_length;
+  const char *blob_data = hb_blob_get_data (blob, &blob_length);
+  if (unlikely (!blob_length))
+    DEBUG_MSG (FT, font, "Font face has empty blob");
+
+  FT_Face ft_face = NULL;
+  FT_Error err = FT_New_Memory_Face (_get_ft_library (),
+				     (const FT_Byte *) blob_data,
+				     blob_length,
+				     hb_face_get_index (font->face),
+				     &ft_face);
+
+  if (unlikely (err)) {
+    hb_blob_destroy (blob);
+    DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
+    return;
+  }
+
+  FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
+
+  FT_Set_Char_Size (ft_face,
+		    font->x_scale, font->y_scale,
+		    font->x_ppem * 72 * 64 / font->x_scale,
+		    font->y_ppem * 72 * 64 / font->y_scale);
+
+  ft_face->generic.data = blob;
+  ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+
+  hb_font_set_funcs (font,
+		     _hb_ft_get_font_funcs (),
+		     ft_face,
+		     (hb_destroy_func_t) FT_Done_Face);
+}
+
+FT_Face
+hb_ft_font_get_face (hb_font_t *font)
+{
+  if (font->destroy == (hb_destroy_func_t) FT_Done_Face ||
+      font->destroy == (hb_destroy_func_t) _do_nothing)
+    return (FT_Face) font->user_data;
+
+  return NULL;
+}
--- a/gfx/harfbuzz/src/hb-ft.h
+++ b/gfx/harfbuzz/src/hb-ft.h
@@ -1,10 +1,10 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -31,28 +31,34 @@
 
 #include "hb-font.h"
 
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
 HB_BEGIN_DECLS
 
-
-hb_font_funcs_t *
-hb_ft_get_font_funcs (void);
+/* Note: FreeType is not thread-safe.  Hence, these functions are not either. */
 
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
-/* Note: This function is not thread-safe */
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face);
 
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy);
 
 
+
+/* Makes an hb_font_t use FreeType internally to implement font functions. */
+void
+hb_ft_font_set_funcs (hb_font_t *font);
+
+FT_Face
+hb_ft_font_get_face (hb_font_t *font);
+
+
 HB_END_DECLS
 
 #endif /* HB_FT_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-glib.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-glib.h"
-
-#include "hb-unicode-private.h"
-
-#include <glib.h>
-
-HB_BEGIN_DECLS
-
-
-static hb_codepoint_t hb_glib_get_mirroring (hb_codepoint_t unicode) { g_unichar_get_mirror_char (unicode, &unicode); return unicode; }
-static hb_category_t hb_glib_get_general_category (hb_codepoint_t unicode) { return g_unichar_type (unicode); }
-static hb_script_t hb_glib_get_script (hb_codepoint_t unicode) { return g_unichar_get_script (unicode); }
-static unsigned int hb_glib_get_combining_class (hb_codepoint_t unicode) { return g_unichar_combining_class (unicode); }
-static unsigned int hb_glib_get_eastasian_width (hb_codepoint_t unicode) { return g_unichar_iswide (unicode); }
-
-
-static hb_unicode_funcs_t glib_ufuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  TRUE, /* immutable */
-  {
-    hb_glib_get_general_category,
-    hb_glib_get_combining_class,
-    hb_glib_get_mirroring,
-    hb_glib_get_script,
-    hb_glib_get_eastasian_width
-  }
-};
-
-hb_unicode_funcs_t *
-hb_glib_get_unicode_funcs (void)
-{
-  return &glib_ufuncs;
-}
-
-
-HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -0,0 +1,349 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-glib.h"
+
+#include "hb-unicode-private.hh"
+
+
+#if !GLIB_CHECK_VERSION(2,29,14)
+static const hb_script_t
+glib_script_to_script[] =
+{
+  HB_SCRIPT_COMMON,
+  HB_SCRIPT_INHERITED,
+  HB_SCRIPT_ARABIC,
+  HB_SCRIPT_ARMENIAN,
+  HB_SCRIPT_BENGALI,
+  HB_SCRIPT_BOPOMOFO,
+  HB_SCRIPT_CHEROKEE,
+  HB_SCRIPT_COPTIC,
+  HB_SCRIPT_CYRILLIC,
+  HB_SCRIPT_DESERET,
+  HB_SCRIPT_DEVANAGARI,
+  HB_SCRIPT_ETHIOPIC,
+  HB_SCRIPT_GEORGIAN,
+  HB_SCRIPT_GOTHIC,
+  HB_SCRIPT_GREEK,
+  HB_SCRIPT_GUJARATI,
+  HB_SCRIPT_GURMUKHI,
+  HB_SCRIPT_HAN,
+  HB_SCRIPT_HANGUL,
+  HB_SCRIPT_HEBREW,
+  HB_SCRIPT_HIRAGANA,
+  HB_SCRIPT_KANNADA,
+  HB_SCRIPT_KATAKANA,
+  HB_SCRIPT_KHMER,
+  HB_SCRIPT_LAO,
+  HB_SCRIPT_LATIN,
+  HB_SCRIPT_MALAYALAM,
+  HB_SCRIPT_MONGOLIAN,
+  HB_SCRIPT_MYANMAR,
+  HB_SCRIPT_OGHAM,
+  HB_SCRIPT_OLD_ITALIC,
+  HB_SCRIPT_ORIYA,
+  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_YI,
+  HB_SCRIPT_TAGALOG,
+  HB_SCRIPT_HANUNOO,
+  HB_SCRIPT_BUHID,
+  HB_SCRIPT_TAGBANWA,
+
+  /* Unicode-4.0 additions */
+  HB_SCRIPT_BRAILLE,
+  HB_SCRIPT_CYPRIOT,
+  HB_SCRIPT_LIMBU,
+  HB_SCRIPT_OSMANYA,
+  HB_SCRIPT_SHAVIAN,
+  HB_SCRIPT_LINEAR_B,
+  HB_SCRIPT_TAI_LE,
+  HB_SCRIPT_UGARITIC,
+
+  /* Unicode-4.1 additions */
+  HB_SCRIPT_NEW_TAI_LUE,
+  HB_SCRIPT_BUGINESE,
+  HB_SCRIPT_GLAGOLITIC,
+  HB_SCRIPT_TIFINAGH,
+  HB_SCRIPT_SYLOTI_NAGRI,
+  HB_SCRIPT_OLD_PERSIAN,
+  HB_SCRIPT_KHAROSHTHI,
+
+  /* Unicode-5.0 additions */
+  HB_SCRIPT_UNKNOWN,
+  HB_SCRIPT_BALINESE,
+  HB_SCRIPT_CUNEIFORM,
+  HB_SCRIPT_PHOENICIAN,
+  HB_SCRIPT_PHAGS_PA,
+  HB_SCRIPT_NKO,
+
+  /* Unicode-5.1 additions */
+  HB_SCRIPT_KAYAH_LI,
+  HB_SCRIPT_LEPCHA,
+  HB_SCRIPT_REJANG,
+  HB_SCRIPT_SUNDANESE,
+  HB_SCRIPT_SAURASHTRA,
+  HB_SCRIPT_CHAM,
+  HB_SCRIPT_OL_CHIKI,
+  HB_SCRIPT_VAI,
+  HB_SCRIPT_CARIAN,
+  HB_SCRIPT_LYCIAN,
+  HB_SCRIPT_LYDIAN,
+
+  /* Unicode-5.2 additions */
+  HB_SCRIPT_AVESTAN,
+  HB_SCRIPT_BAMUM,
+  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
+  HB_SCRIPT_IMPERIAL_ARAMAIC,
+  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
+  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+  HB_SCRIPT_JAVANESE,
+  HB_SCRIPT_KAITHI,
+  HB_SCRIPT_TAI_THAM,
+  HB_SCRIPT_LISU,
+  HB_SCRIPT_MEETEI_MAYEK,
+  HB_SCRIPT_OLD_SOUTH_ARABIAN,
+  HB_SCRIPT_OLD_TURKIC,
+  HB_SCRIPT_SAMARITAN,
+  HB_SCRIPT_TAI_VIET,
+
+  /* Unicode-6.0 additions */
+  HB_SCRIPT_BATAK,
+  HB_SCRIPT_BRAHMI,
+  HB_SCRIPT_MANDAIC
+};
+#endif
+
+hb_script_t
+hb_glib_script_to_script (GUnicodeScript script)
+{
+#if GLIB_CHECK_VERSION(2,29,14)
+  return (hb_script_t) g_unicode_script_to_iso15924 (script);
+#else
+  if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script)))
+    return glib_script_to_script[script];
+
+  if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE))
+    return HB_SCRIPT_INVALID;
+
+  return HB_SCRIPT_UNKNOWN;
+#endif
+}
+
+GUnicodeScript
+hb_glib_script_from_script (hb_script_t script)
+{
+#if GLIB_CHECK_VERSION(2,29,14)
+  return g_unicode_script_from_iso15924 (script);
+#else
+  unsigned int count = ARRAY_LENGTH (glib_script_to_script);
+  for (unsigned int i = 0; i < count; i++)
+    if (glib_script_to_script[i] == script)
+      return (GUnicodeScript) i;
+
+  if (unlikely (script == HB_SCRIPT_INVALID))
+    return G_UNICODE_SCRIPT_INVALID_CODE;
+
+  return G_UNICODE_SCRIPT_UNKNOWN;
+#endif
+}
+
+
+static unsigned int
+hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				 hb_codepoint_t      unicode,
+				 void               *user_data HB_UNUSED)
+
+{
+  return g_unichar_combining_class (unicode);
+}
+
+static unsigned int
+hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				 hb_codepoint_t      unicode,
+				 void               *user_data HB_UNUSED)
+{
+  return g_unichar_iswide (unicode) ? 2 : 1;
+}
+
+static hb_unicode_general_category_t
+hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				  hb_codepoint_t      unicode,
+				  void               *user_data HB_UNUSED)
+
+{
+  /* hb_unicode_general_category_t and GUnicodeType are identical */
+  return (hb_unicode_general_category_t) g_unichar_type (unicode);
+}
+
+static hb_codepoint_t
+hb_glib_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			   hb_codepoint_t      unicode,
+			   void               *user_data HB_UNUSED)
+{
+  g_unichar_get_mirror_char (unicode, &unicode);
+  return unicode;
+}
+
+static hb_script_t
+hb_glib_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			hb_codepoint_t      unicode,
+			void               *user_data HB_UNUSED)
+{
+  return hb_glib_script_to_script (g_unichar_get_script (unicode));
+}
+
+static hb_bool_t
+hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			 hb_codepoint_t      a,
+			 hb_codepoint_t      b,
+			 hb_codepoint_t     *ab,
+			 void               *user_data HB_UNUSED)
+{
+#if GLIB_CHECK_VERSION(2,29,12)
+  return g_unichar_compose (a, b, ab);
+#endif
+
+  /* We don't ifdef-out the fallback code such that compiler always
+   * sees it and makes sure it's compilable. */
+
+  if (!a || !b)
+    return FALSE;
+
+  gchar utf8[12];
+  gchar *normalized;
+  gint len;
+  hb_bool_t ret;
+
+  len = g_unichar_to_utf8 (a, utf8);
+  len += g_unichar_to_utf8 (b, utf8 + len);
+  normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
+  len = g_utf8_strlen (normalized, -1);
+  if (unlikely (!len))
+    return FALSE;
+
+  if (len == 1) {
+    *ab = g_utf8_get_char (normalized);
+    ret = TRUE;
+  } else {
+    ret = FALSE;
+  }
+
+  g_free (normalized);
+  return ret;
+}
+
+static hb_bool_t
+hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			   hb_codepoint_t      ab,
+			   hb_codepoint_t     *a,
+			   hb_codepoint_t     *b,
+			   void               *user_data HB_UNUSED)
+{
+#if GLIB_CHECK_VERSION(2,29,12)
+  return g_unichar_decompose (ab, a, b);
+#endif
+
+  /* We don't ifdef-out the fallback code such that compiler always
+   * sees it and makes sure it's compilable. */
+
+  gchar utf8[6];
+  gchar *normalized;
+  gint len;
+  hb_bool_t ret;
+
+  len = g_unichar_to_utf8 (ab, utf8);
+  normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
+  len = g_utf8_strlen (normalized, -1);
+  if (unlikely (!len))
+    return FALSE;
+
+  if (len == 1) {
+    *a = g_utf8_get_char (normalized);
+    *b = 0;
+    ret = *a != ab;
+  } else if (len == 2) {
+    *a = g_utf8_get_char (normalized);
+    *b = g_utf8_get_char (g_utf8_next_char (normalized));
+    /* Here's the ugly part: if ab decomposes to a single character and
+     * that character decomposes again, we have to detect that and undo
+     * the second part :-(. */
+    gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
+    hb_codepoint_t c = g_utf8_get_char (recomposed);
+    if (c != ab && c != *a) {
+      *a = c;
+      *b = 0;
+    }
+    g_free (recomposed);
+    ret = TRUE;
+  } else {
+    /* If decomposed to more than two characters, take the last one,
+     * and recompose the rest to get the first component. */
+    gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
+    gchar *recomposed;
+    *b = g_utf8_get_char (end);
+    recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
+    /* We expect that recomposed has exactly one character now. */
+    *a = g_utf8_get_char (recomposed);
+    g_free (recomposed);
+    ret = TRUE;
+  }
+
+  g_free (normalized);
+  return ret;
+}
+
+
+extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_glib;
+hb_unicode_funcs_t _hb_glib_unicode_funcs = {
+  HB_OBJECT_HEADER_STATIC,
+
+  NULL, /* parent */
+  TRUE, /* immutable */
+  {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  }
+};
+
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void)
+{
+  return &_hb_glib_unicode_funcs;
+}
+
--- a/gfx/harfbuzz/src/hb-glib.h
+++ b/gfx/harfbuzz/src/hb-glib.h
@@ -1,10 +1,11 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -17,25 +18,34 @@
  *
  * 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_GLIB_H
 #define HB_GLIB_H
 
 #include "hb.h"
+#include <glib.h>
 
 HB_BEGIN_DECLS
 
 
+hb_script_t
+hb_glib_script_to_script (GUnicodeScript script);
+
+GUnicodeScript
+hb_glib_script_from_script (hb_script_t script);
+
+
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void);
 
 
 HB_END_DECLS
 
 #endif /* HB_GLIB_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject-enums.cc.tmpl
@@ -0,0 +1,74 @@
+/*** BEGIN file-header ***/
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+/* g++ didn't like older gtype.h gcc-only code path. */
+#include <glib.h>
+#if !GLIB_CHECK_VERSION(2,29,16)
+#undef __GNUC__
+#undef __GNUC_MINOR__
+#define __GNUC__ 2
+#define __GNUC_MINOR__ 6
+#endif
+
+#include "hb-gobject.h"
+
+/*** 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;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      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 =
+        g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject-structs.cc
@@ -0,0 +1,63 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+/* g++ didn't like older gtype.h gcc-only code path. */
+#include <glib.h>
+#if !GLIB_CHECK_VERSION(2,29,16)
+#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) \
+GType \
+underscore_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); \
+   } \
+   return type; \
+}
+
+#define HB_DEFINE_BOXED_TYPE(name) \
+	_HB_DEFINE_BOXED_TYPE (hb_##name, hb_gobject_##name, hb_##name##_reference, hb_##name##_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)
+
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject.h
@@ -0,0 +1,68 @@
+/*
+ * 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
+#define HB_GOBJECT_H
+
+#include "hb.h"
+#include <glib-object.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
+
+#endif /* HB_GOBJECT_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-graphite.cc
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2009  Martin Hosken
- * Copyright (C) 2009  SIL International
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * 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.
- */
-
-#include <graphite/GrClient.h>
-#include <graphite/ITextSource.h>
-#include <graphite/GrData.h>
-#include <graphite/GrConstants.h>
-#include <graphite/Segment.h>
-#include "hb-buffer-private.hh"
-#include "hb-font-private.h"
-#include "hb-graphite.h"
-#include <map>
-
-HB_BEGIN_DECLS
-
-
-namespace TtfUtil
-{
-extern int FontAscent(const void *pOS2);
-extern int FontDescent(const void *pOS2);
-extern int DesignUnits(const void *pHead);
-extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic);
-}
-
-typedef struct _featureSetting {
-    unsigned int id;
-    int value;
-} featureSetting;
-
-class HbGrBufferTextSrc : public gr::ITextSource
-{
-public:
-  HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
-  {
-    hb_feature_t *aFeat = feats;
-    featureSetting *aNewFeat;
-
-    buffer = hb_buffer_reference(buff);
-    features = new featureSetting[num_features];
-    nFeatures = num_features;
-    aNewFeat = features;
-    for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++)
-    {
-        aNewFeat->id = aFeat->tag;
-        aNewFeat->value = aFeat->value;
-    }
-  };
-  ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; };
-  virtual gr::UtfType utfEncodingForm() { return gr::kutf32; };
-  virtual size_t getLength() { return buffer->len; };
-  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer)
-  {
-    assert(cch <= buffer->len);
-    if (cch > buffer->len)
-      return 0;
-    for (unsigned int i = ichMin; i < ichMin + cch; i++)
-      prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
-    return (cch - ichMin);
-  };
-  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer) { return 0 ;};
-  virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) { return 0; };
-  virtual bool getRightToLeft(gr::toffset ich)
-  { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; };
-  virtual unsigned int getDirectionDepth(gr::toffset ich)
-  { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; };
-  virtual float getVerticalOffset(gr::toffset ich) { return 0; };
-  virtual gr::isocode getLanguage(gr::toffset ich)
-  {
-    gr::isocode aLang;
-    char *p = (char *)(buffer->language);
-    int i;
-    for (i = 0; i < 4; i++)
-    {
-      if (p != NULL)
-        aLang.rgch[i] = *p;
-      else
-        aLang.rgch[i] = 0;
-      if (p && *p)
-        p++;
-    }
-    return aLang;
-  }
-
-  virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich)
-  { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); };
-  virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset)
-  {
-    featureSetting *aFeat = features;
-    for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++)
-    {
-      prgfset->id = aFeat->id;
-      prgfset->value = aFeat->value;
-    }
-    return nFeatures;
-  }
-  virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; };
-
-private:
-  hb_buffer_t   *buffer;
-  featureSetting   *features;
-  unsigned int nFeatures;
-};
-
-class HbGrFont : public gr::Font
-{
-public:
-  HbGrFont(hb_font_t *font, hb_face_t *face) : gr::Font()
-  { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); };
-  ~HbGrFont()
-  {
-    std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin();
-    while (p != m_blobs.end())
-    { hb_blob_destroy((p++)->second); }
-    hb_font_destroy(m_font);
-    hb_face_destroy(m_face);
-  };
-  HbGrFont (const HbGrFont &font) : gr::Font(font)
-  {
-    *this = font;
-    m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs);
-    std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin();
-    while (p != m_blobs.end()) { hb_blob_reference((*p++).second); }
-    hb_font_reference(m_font);
-    hb_face_reference(m_face);
-  };
-  virtual HbGrFont *copyThis() { return new HbGrFont(*this); };
-  virtual bool bold() { return m_bold; };
-  virtual bool italic() { return m_italic; };
-  virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; };
-  virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return desc; };
-  virtual float height()
-  { float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); };
-  virtual unsigned int getDPIx() { return m_font->x_ppem; };
-  virtual unsigned int getDPIy() { return m_font->y_ppem; };
-  virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize)
-  {
-    hb_blob_t *blob;
-    std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID);
-    if (p == m_blobs.end())
-    {
-      blob = hb_face_get_table(m_face, (hb_tag_t)tableID);
-      m_blobs[(hb_tag_t)tableID] = blob;
-    }
-    else
-    { blob = p->second; }
-
-    const char *res = hb_blob_lock(blob);
-    if (pcbsize)
-      *pcbsize = hb_blob_get_length(blob);
-    hb_blob_unlock(blob);
-    return (const void *)res;
-  }
-
-  virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare)
-  {
-    if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare;
-    if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare;
-    if (pEmSquare) *pEmSquare = m_font->x_scale;
-  }
-  virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn)
-  {
-    hb_position_t x, y;
-    hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y);
-    pointReturn.x = (float)x;
-    pointReturn.y = (float)y;
-  }
-
-  virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances)
-  {
-    hb_glyph_metrics_t metrics;
-    hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics);
-    boundingBox.top = (metrics.y_offset + metrics.height);
-    boundingBox.bottom = metrics.y_offset;
-    boundingBox.left = metrics.x_offset;
-    boundingBox.right = (metrics.x_offset + metrics.width);
-    advances.x = metrics.x_advance;
-    advances.y = metrics.y_advance;
-//    fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_offset, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics.y_advance);
-  }
-
-private:
-  HB_INTERNAL void initfont();
-
-  hb_font_t *m_font;
-  hb_face_t *m_face;
-  float m_ascent;
-  float m_descent;
-  float m_emsquare;
-  bool m_bold;
-  bool m_italic;
-  std::map<hb_tag_t, hb_blob_t *> m_blobs;
-};
-
-void HbGrFont::initfont()
-{
-  const void *pOS2 = getTable(gr::kttiOs2, NULL);
-  const void *pHead = getTable(gr::kttiHead, NULL);
-  TtfUtil::FontOs2Style(pOS2, m_bold, m_italic);
-  m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2));
-  m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2));
-  m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead));
-}
-
-void
-hb_graphite_shape (hb_font_t    *font,
-		   hb_face_t    *face,
-		   hb_buffer_t  *buffer,
-		   hb_feature_t *features,
-		   unsigned int  num_features)
-{
-  /* create text source */
-  HbGrBufferTextSrc   textSrc(buffer, features, num_features);
-
-  /* create grfont */
-  HbGrFont          grfont(font, face);
-
-  /* create segment */
-  int *firsts;
-  bool *flags;
-  int numChars;
-  int numGlyphs;
-  gr::LayoutEnvironment layout;
-  std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range;
-  gr::GlyphIterator iGlyph;
-  hb_codepoint_t *glyph_infos, *pGlyph;
-  hb_glyph_position_t *pPosition;
-  int cGlyph = 0;
-  int cChar = 0;
-
-  layout.setStartOfLine(0);
-  layout.setEndOfLine(0);
-  layout.setDumbFallback(true);
-  layout.setJustifier(NULL);
-  layout.setRightToLeft(false);
-
-  gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0,
-        static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL);
-
-  /* fill in buffer from segment */
-  _hb_buffer_clear_output(buffer);
-  pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs);
-  firsts = new int[numChars];
-  flags = new bool[numGlyphs];
-  glyph_infos = new hb_codepoint_t[numGlyphs];
-  hb_buffer_ensure(buffer, numGlyphs);
-  pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL);
-  glyph_range = pSegment.glyphs();
-  for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second;
-        iGlyph++, pGlyph++)
-  { *pGlyph = iGlyph->glyphID(); }
-
-  while (cGlyph < numGlyphs)
-  {
-    if (flags[cGlyph])
-    {
-        int oldcChar = cChar++;
-        int oldcGlyph = cGlyph++;
-        while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++;
-        while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++;
-        _hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyph,
-                glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF);
-    }
-    else
-    { cGlyph++; }   /* This should never happen */
-  }
-
-  float curradvx = 0., curradvy = 0.;
-  for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first;
-        iGlyph != glyph_range.second; pPosition++, iGlyph++)
-  {
-    pPosition->x_offset = iGlyph->origin() - curradvx;
-    pPosition->y_offset = iGlyph->yOffset() - curradvy;
-    pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth();
-    pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight();
-    if (pPosition->x_advance < 0 && iGlyph->logicalIndex() != iGlyph->attachedClusterBase()->logicalIndex())
-        pPosition->x_advance = 0;
-    curradvx += pPosition->x_advance;
-    curradvy += pPosition->y_advance;
-//    fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
-  }
-
-  delete[] glyph_infos;
-  delete[] firsts;
-  delete[] flags;
-}
-
-
-HB_END_DECLS
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-graphite.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2009, Martin Hosken
- * Copyright (C) 2009, SIL International
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * 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_GRAPHITE_H
-#define HB_GRAPHITE_H
-
-#include "hb-shape.h"
-
-HB_BEGIN_DECLS
-
-
-#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
-
-void hb_graphite_shape (hb_font_t    *font,
-			hb_face_t    *face,
-			hb_buffer_t  *buffer,
-			hb_feature_t *features,
-			unsigned int  num_features);
-
-
-HB_END_DECLS
-
-#endif /* HB_GRAPHITE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -0,0 +1,348 @@
+/*
+ * Copyright © 2011  Martin Hosken
+ * Copyright © 2011  SIL International
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-graphite2.h"
+
+#include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
+#include "hb-ot-tag.h"
+
+#include <graphite2/Font.h>
+#include <graphite2/Segment.h>
+
+
+struct hb_gr_cluster_t {
+  unsigned int base_char;
+  unsigned int num_chars;
+  unsigned int base_glyph;
+  unsigned int num_glyphs;
+};
+
+
+typedef struct hb_gr_tablelist_t {
+  hb_blob_t   *blob;
+  struct hb_gr_tablelist_t *next;
+  unsigned int tag;
+} hb_gr_tablelist_t;
+
+static struct hb_gr_face_data_t {
+  hb_face_t         *face;
+  gr_face           *grface;
+  hb_gr_tablelist_t *tlist;
+} _hb_gr_face_data_nil = {NULL, NULL};
+
+static struct hb_gr_font_data_t {
+  gr_font   *grfont;
+  gr_face   *grface;
+} _hb_gr_font_data_nil = {NULL, NULL};
+
+
+static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *len)
+{
+  hb_gr_tablelist_t *pl = NULL, *p;
+  hb_gr_face_data_t *face = (hb_gr_face_data_t *) data;
+  hb_gr_tablelist_t *tlist = face->tlist;
+
+  for (p = tlist; p; p = p->next)
+    if (p->tag == tag ) {
+      unsigned int tlen;
+      const char *d = hb_blob_get_data (p->blob, &tlen);
+      *len = tlen;
+      return d;
+    } else
+      pl = p;
+
+  if (!face->face)
+    return NULL;
+  hb_blob_t *blob = hb_face_reference_table (face->face, tag);
+
+  if (!pl || pl->blob)
+  {
+    p = (hb_gr_tablelist_t *) malloc (sizeof (hb_gr_tablelist_t));
+    if (!p) {
+      hb_blob_destroy (blob);
+      return NULL;
+    }
+    p->next = NULL;
+    if (pl)
+      pl->next = p;
+    else
+      face->tlist = p;
+    pl = p;
+  }
+  pl->blob = blob;
+  pl->tag = tag;
+
+  unsigned int tlen;
+  const char *d = hb_blob_get_data (blob, &tlen);
+  *len = tlen;
+  return d;
+}
+
+static float hb_gr_get_advance (const void *hb_font, unsigned short gid)
+{
+  return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid);
+}
+
+static void _hb_gr_face_data_destroy (void *data)
+{
+  hb_gr_face_data_t *f = (hb_gr_face_data_t *) data;
+  hb_gr_tablelist_t *tlist = f->tlist;
+  while (tlist)
+  {
+    hb_gr_tablelist_t *old = tlist;
+    hb_blob_destroy (tlist->blob);
+    tlist = tlist->next;
+    free (old);
+  }
+  gr_face_destroy (f->grface);
+}
+
+static void _hb_gr_font_data_destroy (void *data)
+{
+  hb_gr_font_data_t *f = (hb_gr_font_data_t *) data;
+
+  gr_font_destroy (f->grfont);
+}
+
+static hb_user_data_key_t hb_gr_data_key;
+
+static hb_gr_face_data_t *
+_hb_gr_face_get_data (hb_face_t *face)
+{
+  hb_gr_face_data_t *data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
+  if (likely (data)) return data;
+
+  data = (hb_gr_face_data_t *) calloc (1, sizeof (hb_gr_face_data_t));
+  if (unlikely (!data))
+    return &_hb_gr_face_data_nil;
+
+
+  hb_blob_t *silf_blob = hb_face_reference_table (face, HB_GRAPHITE_TAG_Silf);
+  if (!hb_blob_get_length (silf_blob))
+  {
+    hb_blob_destroy (silf_blob);
+    return &_hb_gr_face_data_nil;
+  }
+
+  data->face = face;
+  data->grface = gr_make_face (data, &hb_gr_get_table, gr_face_default);
+
+
+  if (unlikely (!hb_face_set_user_data (face, &hb_gr_data_key, data,
+					(hb_destroy_func_t) _hb_gr_face_data_destroy,
+					FALSE)))
+  {
+    _hb_gr_face_data_destroy (data);
+    data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
+    if (data)
+      return data;
+    else
+      return &_hb_gr_face_data_nil;
+  }
+
+  return data;
+}
+
+static hb_gr_font_data_t *
+_hb_gr_font_get_data (hb_font_t *font)
+{
+  hb_gr_font_data_t *data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
+  if (likely (data)) return data;
+
+  data = (hb_gr_font_data_t *) calloc (1, sizeof (hb_gr_font_data_t));
+  if (unlikely (!data))
+    return &_hb_gr_font_data_nil;
+
+
+  hb_blob_t *silf_blob = hb_face_reference_table (font->face, HB_GRAPHITE_TAG_Silf);
+  if (!hb_blob_get_length (silf_blob))
+  {
+    hb_blob_destroy (silf_blob);
+    return &_hb_gr_font_data_nil;
+  }
+
+  data->grface = _hb_gr_face_get_data (font->face)->grface;
+  int scale;
+  hb_font_get_scale (font, &scale, NULL);
+  data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface);
+
+
+  if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data,
+					(hb_destroy_func_t) _hb_gr_font_data_destroy,
+					FALSE)))
+  {
+    _hb_gr_font_data_destroy (data);
+    data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
+    if (data)
+      return data;
+    else
+      return &_hb_gr_font_data_nil;
+  }
+
+  return data;
+}
+
+
+hb_bool_t
+hb_graphite_shape (hb_font_t          *font,
+		   hb_buffer_t        *buffer,
+		   const hb_feature_t *features,
+		   unsigned int        num_features,
+		   const char * const *shaper_options)
+{
+
+  buffer->guess_properties ();
+
+  hb_gr_font_data_t *data = _hb_gr_font_get_data (font);
+  if (!data->grface) return FALSE;
+
+  unsigned int charlen;
+  hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen);
+
+  int success = 0;
+
+  if (!charlen) return TRUE;
+
+  const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
+  const char *lang_end = strchr (lang, '-');
+  int lang_len = lang_end ? lang_end - lang : -1;
+  gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
+
+  while (num_features--)
+  {
+    const gr_feature_ref *fref = gr_face_find_fref (data->grface, features->tag);
+    if (fref)
+      gr_fref_set_feature_value (fref, features->value, feats);
+    features++;
+  }
+
+  unsigned short *gids = NULL;
+  hb_gr_cluster_t *clusters = NULL;
+  gr_segment *seg = NULL;
+  uint32_t *text = NULL;
+  unsigned short *pg;
+  const gr_slot *is;
+  unsigned int ci = 0, ic = 0;
+  float curradvx = 0., curradvy = 0.;
+  unsigned int glyphlen = 0;
+  unsigned int *p;
+
+  text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t));
+  if (!text) goto dieout;
+
+  p = text;
+  for (unsigned int i = 0; i < charlen; ++i)
+    *p++ = bufferi++->codepoint;
+  *p = 0;
+
+  hb_tag_t script_tag[2];
+  hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
+
+  seg = gr_make_seg (data->grfont, data->grface,
+		     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
+		     feats,
+		     gr_utf32, text, charlen,
+		     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
+  if (!seg) goto dieout;
+
+  glyphlen = gr_seg_n_slots (seg);
+  clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t));
+  if (!glyphlen || !clusters) goto dieout;
+
+  gids = (uint16_t *) malloc (glyphlen * sizeof (uint16_t));
+  if (!gids) goto dieout;
+
+  pg = gids;
+  for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
+  {
+    unsigned int before = gr_slot_before (is);
+    unsigned int after = gr_slot_after (is);
+    *pg = gr_slot_gid (is);
+    pg++;
+    while (clusters[ci].base_char > before && ci)
+    {
+      clusters[ci-1].num_chars += clusters[ci].num_chars;
+      clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
+      ci--;
+    }
+
+    if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
+    {
+      hb_gr_cluster_t *c = clusters + ci + 1;
+      c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
+      c->num_chars = before - c->base_char;
+      c->base_glyph = ic;
+      c->num_glyphs = 0;
+      ci++;
+    }
+    clusters[ci].num_glyphs++;
+
+    if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
+	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
+  }
+  ci++;
+
+  buffer->clear_output ();
+  for (unsigned int i = 0; i < ci; ++i)
+    buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph);
+  buffer->swap_buffers ();
+
+  hb_glyph_position_t *pPos;
+  for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
+       is; pPos++, is = gr_slot_next_in_segment (is))
+  {
+    pPos->x_offset = gr_slot_origin_X(is) - curradvx;
+    pPos->y_offset = gr_slot_origin_Y(is) - curradvy;
+    pPos->x_advance = gr_slot_advance_X(is, data->grface, data->grfont);
+    pPos->y_advance = gr_slot_advance_Y(is, data->grface, data->grfont);
+//    if (pPos->x_advance < 0 && gr_slot_attached_to(is))
+//      pPos->x_advance = 0;
+    curradvx += pPos->x_advance;
+    curradvy += pPos->y_advance;
+  }
+  pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+
+  /* TODO(behdad):
+   * This shaper is badly broken with RTL text.  It returns glyphs
+   * in the logical order!
+   */
+//  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+//    hb_buffer_reverse (buffer);
+
+  success = 1;
+
+dieout:
+  if (gids) free (gids);
+  if (clusters) free (clusters);
+  if (seg) gr_seg_destroy (seg);
+  if (text) free (text);
+  return success;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-graphite2.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011  Martin Hosken
+ * Copyright (C) 2011  SIL International
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * 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.
+ */
+
+#ifndef HB_GRAPHITE2_H
+#define HB_GRAPHITE2_H
+
+#include "hb-common.h"
+#include "hb-shape.h"
+
+HB_BEGIN_DECLS
+
+
+#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
+
+hb_bool_t
+hb_graphite_shape (hb_font_t          *font,
+		   hb_buffer_t        *buffer,
+		   const hb_feature_t *features,
+		   unsigned int        num_features,
+		   const char * const *shaper_options);
+
+HB_END_DECLS
+
+#endif /* HB_GRAPHITE2_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-icu.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- * Copyright (C) 2009  Keith Stribley <devel@thanlwinsoft.org>
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-icu.h"
-
-#include "hb-unicode-private.h"
-
-#include <unicode/uversion.h>
-#include <unicode/uchar.h>
-#include <unicode/uscript.h>
-
-HB_BEGIN_DECLS
-
-
-static hb_codepoint_t hb_icu_get_mirroring (hb_codepoint_t unicode) { return u_charMirror(unicode); }
-static unsigned int hb_icu_get_combining_class (hb_codepoint_t unicode) { return u_getCombiningClass (unicode); }
-
-static unsigned int
-hb_icu_get_eastasian_width (hb_codepoint_t unicode)
-{
-  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
-  {
-  case U_EA_WIDE:
-  case U_EA_FULLWIDTH:
-    return 2;
-  case U_EA_NEUTRAL:
-  case U_EA_AMBIGUOUS:
-  case U_EA_HALFWIDTH:
-  case U_EA_NARROW:
-    return 1;
-  }
-  return 1;
-}
-
-static hb_category_t
-hb_icu_get_general_category (hb_codepoint_t unicode)
-{
-  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
-  {
-  case U_UNASSIGNED:			return HB_CATEGORY_UNASSIGNED;
-
-  case U_UPPERCASE_LETTER:		return HB_CATEGORY_UPPERCASE_LETTER;	/* Lu */
-  case U_LOWERCASE_LETTER:		return HB_CATEGORY_LOWERCASE_LETTER;	/* Ll */
-  case U_TITLECASE_LETTER:		return HB_CATEGORY_TITLECASE_LETTER;	/* Lt */
-  case U_MODIFIER_LETTER:		return HB_CATEGORY_MODIFIER_LETTER;	/* Lm */
-  case U_OTHER_LETTER:			return HB_CATEGORY_OTHER_LETTER;	/* Lo */
-
-  case U_NON_SPACING_MARK:		return HB_CATEGORY_NON_SPACING_MARK;	/* Mn */
-  case U_ENCLOSING_MARK:		return HB_CATEGORY_ENCLOSING_MARK;	/* Me */
-  case U_COMBINING_SPACING_MARK:	return HB_CATEGORY_COMBINING_MARK;	/* Mc */
-
-  case U_DECIMAL_DIGIT_NUMBER:		return HB_CATEGORY_DECIMAL_NUMBER;	/* Nd */
-  case U_LETTER_NUMBER:			return HB_CATEGORY_LETTER_NUMBER;	/* Nl */
-  case U_OTHER_NUMBER:			return HB_CATEGORY_OTHER_NUMBER;	/* No */
-
-  case U_SPACE_SEPARATOR:		return HB_CATEGORY_SPACE_SEPARATOR;	/* Zs */
-  case U_LINE_SEPARATOR:		return HB_CATEGORY_LINE_SEPARATOR;	/* Zl */
-  case U_PARAGRAPH_SEPARATOR:		return HB_CATEGORY_PARAGRAPH_SEPARATOR;	/* Zp */
-
-  case U_CONTROL_CHAR:			return HB_CATEGORY_CONTROL;		/* Cc */
-  case U_FORMAT_CHAR:			return HB_CATEGORY_FORMAT;		/* Cf */
-  case U_PRIVATE_USE_CHAR:		return HB_CATEGORY_PRIVATE_USE;		/* Co */
-  case U_SURROGATE:			return HB_CATEGORY_SURROGATE;		/* Cs */
-
-
-  case U_DASH_PUNCTUATION:		return HB_CATEGORY_DASH_PUNCTUATION;	/* Pd */
-  case U_START_PUNCTUATION:		return HB_CATEGORY_OPEN_PUNCTUATION;	/* Ps */
-  case U_END_PUNCTUATION:		return HB_CATEGORY_CLOSE_PUNCTUATION;	/* Pe */
-  case U_CONNECTOR_PUNCTUATION:		return HB_CATEGORY_CONNECT_PUNCTUATION;	/* Pc */
-  case U_OTHER_PUNCTUATION:		return HB_CATEGORY_OTHER_PUNCTUATION;	/* Po */
-
-  case U_MATH_SYMBOL:			return HB_CATEGORY_MATH_SYMBOL;		/* Sm */
-  case U_CURRENCY_SYMBOL:		return HB_CATEGORY_CURRENCY_SYMBOL;	/* Sc */
-  case U_MODIFIER_SYMBOL:		return HB_CATEGORY_MODIFIER_SYMBOL;	/* Sk */
-  case U_OTHER_SYMBOL:			return HB_CATEGORY_OTHER_SYMBOL;	/* So */
-
-  case U_INITIAL_PUNCTUATION:		return HB_CATEGORY_INITIAL_PUNCTUATION;	/* Pi */
-  case U_FINAL_PUNCTUATION:		return HB_CATEGORY_FINAL_PUNCTUATION;	/* Pf */
-  }
-
-  return HB_CATEGORY_UNASSIGNED;
-}
-
-static hb_script_t
-hb_icu_get_script (hb_codepoint_t unicode)
-{
-  UErrorCode status = U_ZERO_ERROR;
-  UScriptCode scriptCode = uscript_getScript(unicode, &status);
-  switch ((int) scriptCode)
-  {
-#define CHECK_ICU_VERSION(major, minor) \
-	U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
-#define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
-#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
-  MATCH_SCRIPT (INVALID_CODE);
-  MATCH_SCRIPT (COMMON);             /* Zyyy */
-  MATCH_SCRIPT (INHERITED);          /* Qaai */
-  MATCH_SCRIPT (ARABIC);             /* Arab */
-  MATCH_SCRIPT (ARMENIAN);           /* Armn */
-  MATCH_SCRIPT (BENGALI);            /* Beng */
-  MATCH_SCRIPT (BOPOMOFO);           /* Bopo */
-  MATCH_SCRIPT (CHEROKEE);           /* Cher */
-  MATCH_SCRIPT (COPTIC);             /* Qaac */
-  MATCH_SCRIPT (CYRILLIC);           /* Cyrl (Cyrs) */
-  MATCH_SCRIPT (DESERET);            /* Dsrt */
-  MATCH_SCRIPT (DEVANAGARI);         /* Deva */
-  MATCH_SCRIPT (ETHIOPIC);           /* Ethi */
-  MATCH_SCRIPT (GEORGIAN);           /* Geor (Geon); Geoa) */
-  MATCH_SCRIPT (GOTHIC);             /* Goth */
-  MATCH_SCRIPT (GREEK);              /* Grek */
-  MATCH_SCRIPT (GUJARATI);           /* Gujr */
-  MATCH_SCRIPT (GURMUKHI);           /* Guru */
-  MATCH_SCRIPT (HAN);                /* Hani */
-  MATCH_SCRIPT (HANGUL);             /* Hang */
-  MATCH_SCRIPT (HEBREW);             /* Hebr */
-  MATCH_SCRIPT (HIRAGANA);           /* Hira */
-  MATCH_SCRIPT (KANNADA);            /* Knda */
-  MATCH_SCRIPT (KATAKANA);           /* Kana */
-  MATCH_SCRIPT (KHMER);              /* Khmr */
-  MATCH_SCRIPT (LAO);                /* Laoo */
-  MATCH_SCRIPT (LATIN);              /* Latn (Latf); Latg) */
-  MATCH_SCRIPT (MALAYALAM);          /* Mlym */
-  MATCH_SCRIPT (MONGOLIAN);          /* Mong */
-  MATCH_SCRIPT (MYANMAR);            /* Mymr */
-  MATCH_SCRIPT (OGHAM);              /* Ogam */
-  MATCH_SCRIPT (OLD_ITALIC);         /* Ital */
-  MATCH_SCRIPT (ORIYA);              /* Orya */
-  MATCH_SCRIPT (RUNIC);              /* Runr */
-  MATCH_SCRIPT (SINHALA);            /* Sinh */
-  MATCH_SCRIPT (SYRIAC);             /* Syrc (Syrj, Syrn); Syre) */
-  MATCH_SCRIPT (TAMIL);              /* Taml */
-  MATCH_SCRIPT (TELUGU);             /* Telu */
-  MATCH_SCRIPT (THAANA);             /* Thaa */
-  MATCH_SCRIPT (THAI);               /* Thai */
-  MATCH_SCRIPT (TIBETAN);            /* Tibt */
-  MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
-  MATCH_SCRIPT (YI);                 /* Yiii */
-  MATCH_SCRIPT (TAGALOG);            /* Tglg */
-  MATCH_SCRIPT (HANUNOO);            /* Hano */
-  MATCH_SCRIPT (BUHID);              /* Buhd */
-  MATCH_SCRIPT (TAGBANWA);           /* Tagb */
-
-  /* Unicode-4.0 additions */
-  MATCH_SCRIPT (BRAILLE);            /* Brai */
-  MATCH_SCRIPT (CYPRIOT);            /* Cprt */
-  MATCH_SCRIPT (LIMBU);              /* Limb */
-  MATCH_SCRIPT (OSMANYA);            /* Osma */
-  MATCH_SCRIPT (SHAVIAN);            /* Shaw */
-  MATCH_SCRIPT (LINEAR_B);           /* Linb */
-  MATCH_SCRIPT (TAI_LE);             /* Tale */
-  MATCH_SCRIPT (UGARITIC);           /* Ugar */
-
-  /* Unicode-4.1 additions */
-  MATCH_SCRIPT (NEW_TAI_LUE);        /* Talu */
-  MATCH_SCRIPT (BUGINESE);           /* Bugi */
-  MATCH_SCRIPT (GLAGOLITIC);         /* Glag */
-  MATCH_SCRIPT (TIFINAGH);           /* Tfng */
-  MATCH_SCRIPT (SYLOTI_NAGRI);       /* Sylo */
-  MATCH_SCRIPT (OLD_PERSIAN);        /* Xpeo */
-  MATCH_SCRIPT (KHAROSHTHI);         /* Khar */
-
-  /* Unicode-5.0 additions */
-  MATCH_SCRIPT (UNKNOWN);            /* Zzzz */
-  MATCH_SCRIPT (BALINESE);           /* Bali */
-  MATCH_SCRIPT (CUNEIFORM);          /* Xsux */
-  MATCH_SCRIPT (PHOENICIAN);         /* Phnx */
-  MATCH_SCRIPT (PHAGS_PA);           /* Phag */
-  MATCH_SCRIPT (NKO);                /* Nkoo */
-
-  /* Unicode-5.1 additions */
-  MATCH_SCRIPT (KAYAH_LI);           /* Kali */
-  MATCH_SCRIPT (LEPCHA);             /* Lepc */
-  MATCH_SCRIPT (REJANG);             /* Rjng */
-  MATCH_SCRIPT (SUNDANESE);          /* Sund */
-  MATCH_SCRIPT (SAURASHTRA);         /* Saur */
-  MATCH_SCRIPT (CHAM);               /* Cham */
-  MATCH_SCRIPT (OL_CHIKI);           /* Olck */
-  MATCH_SCRIPT (VAI);                /* Vaii */
-  MATCH_SCRIPT (CARIAN);             /* Cari */
-  MATCH_SCRIPT (LYCIAN);             /* Lyci */
-  MATCH_SCRIPT (LYDIAN);             /* Lydi */
-
-  /* Unicode-5.2 additions */
-  MATCH_SCRIPT (AVESTAN);                /* Avst */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (BAMUM);                  /* Bamu */
-#endif
-  MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS);   /* Egyp */
-  MATCH_SCRIPT (IMPERIAL_ARAMAIC);       /* Armi */
-  MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI);  /* Phli */
-  MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
-  MATCH_SCRIPT (JAVANESE);               /* Java */
-  MATCH_SCRIPT (KAITHI);                 /* Kthi */
-  MATCH_SCRIPT2(LANNA, TAI_THAM);        /* Lana */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (LISU);                   /* Lisu */
-#endif
-  MATCH_SCRIPT2(MEITEI_MAYEK, MEETEI_MAYEK);/* Mtei */
-#if CHECK_ICU_VERSION (4, 4)
-  MATCH_SCRIPT (OLD_SOUTH_ARABIAN);      /* Sarb */
-#endif
-  MATCH_SCRIPT2(ORKHON, OLD_TURKIC);     /* Orkh */
-  MATCH_SCRIPT (SAMARITAN);              /* Samr */
-  MATCH_SCRIPT (TAI_VIET);               /* Tavt */
-
-  /* Unicode-6.0 additions */
-  MATCH_SCRIPT (BATAK);                  /* Batk */
-  MATCH_SCRIPT (BRAHMI);                 /* Brah */
-  MATCH_SCRIPT2(MANDAEAN, MANDAIC);      /* Mand */
-
-  }
-  return HB_SCRIPT_UNKNOWN;
-}
-
-static hb_unicode_funcs_t icu_ufuncs = {
-  HB_REFERENCE_COUNT_INVALID, /* ref_count */
-  TRUE, /* immutable */
-  {
-    hb_icu_get_general_category,
-    hb_icu_get_combining_class,
-    hb_icu_get_mirroring,
-    hb_icu_get_script,
-    hb_icu_get_eastasian_width
-  }
-};
-
-hb_unicode_funcs_t *
-hb_icu_get_unicode_funcs (void)
-{
-  return &icu_ufuncs;
-}
-
-
-HB_END_DECLS
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-icu.cc
@@ -0,0 +1,291 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2009  Keith Stribley
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-icu.h"
+
+#include "hb-unicode-private.hh"
+
+#include <unicode/uversion.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <unicode/ustring.h>
+
+
+
+hb_script_t
+hb_icu_script_to_script (UScriptCode script)
+{
+  if (unlikely (script == USCRIPT_INVALID_CODE))
+    return HB_SCRIPT_INVALID;
+
+  return hb_script_from_string (uscript_getShortName (script), -1);
+}
+
+UScriptCode
+hb_icu_script_from_script (hb_script_t script)
+{
+  if (unlikely (script == HB_SCRIPT_INVALID))
+    return USCRIPT_INVALID_CODE;
+
+  for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++)
+    if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
+      return (UScriptCode) i;
+
+  return USCRIPT_UNKNOWN;
+}
+
+
+static unsigned int
+hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				hb_codepoint_t      unicode,
+				void               *user_data HB_UNUSED)
+
+{
+  return u_getCombiningClass (unicode);
+}
+
+static unsigned int
+hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				hb_codepoint_t      unicode,
+				void               *user_data HB_UNUSED)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
+  {
+  case U_EA_WIDE:
+  case U_EA_FULLWIDTH:
+    return 2;
+  case U_EA_NEUTRAL:
+  case U_EA_AMBIGUOUS:
+  case U_EA_HALFWIDTH:
+  case U_EA_NARROW:
+    return 1;
+  }
+  return 1;
+}
+
+static hb_unicode_general_category_t
+hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+				 hb_codepoint_t      unicode,
+				 void               *user_data HB_UNUSED)
+{
+  switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
+  {
+  case U_UNASSIGNED:			return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+
+  case U_UPPERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
+  case U_LOWERCASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
+  case U_TITLECASE_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
+  case U_MODIFIER_LETTER:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
+  case U_OTHER_LETTER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
+
+  case U_NON_SPACING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
+  case U_ENCLOSING_MARK:		return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+  case U_COMBINING_SPACING_MARK:	return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
+
+  case U_DECIMAL_DIGIT_NUMBER:		return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
+  case U_LETTER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
+  case U_OTHER_NUMBER:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
+
+  case U_SPACE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+  case U_LINE_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
+  case U_PARAGRAPH_SEPARATOR:		return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
+
+  case U_CONTROL_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
+  case U_FORMAT_CHAR:			return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+  case U_PRIVATE_USE_CHAR:		return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
+  case U_SURROGATE:			return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
+
+
+  case U_DASH_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
+  case U_START_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
+  case U_END_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
+  case U_CONNECTOR_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
+  case U_OTHER_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
+
+  case U_MATH_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
+  case U_CURRENCY_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
+  case U_MODIFIER_SYMBOL:		return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
+  case U_OTHER_SYMBOL:			return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
+
+  case U_INITIAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
+  case U_FINAL_PUNCTUATION:		return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
+  }
+
+  return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
+}
+
+static hb_codepoint_t
+hb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			  hb_codepoint_t      unicode,
+			  void               *user_data HB_UNUSED)
+{
+  return u_charMirror(unicode);
+}
+
+static hb_script_t
+hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+		       hb_codepoint_t      unicode,
+		       void               *user_data HB_UNUSED)
+{
+  UErrorCode status = U_ZERO_ERROR;
+  UScriptCode scriptCode = uscript_getScript(unicode, &status);
+
+  if (unlikely (U_FAILURE (status)))
+    return HB_SCRIPT_UNKNOWN;
+
+  return hb_icu_script_to_script (scriptCode);
+}
+
+static hb_bool_t
+hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			hb_codepoint_t      a,
+			hb_codepoint_t      b,
+			hb_codepoint_t     *ab,
+			void               *user_data HB_UNUSED)
+{
+  if (!a || !b)
+    return FALSE;
+
+  UChar utf16[4], normalized[5];
+  int len;
+  hb_bool_t ret, err;
+  UErrorCode icu_err;
+
+  len = 0;
+  err = FALSE;
+  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
+  if (err) return FALSE;
+  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
+  if (err) return FALSE;
+
+  icu_err = U_ZERO_ERROR;
+  len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  if (U_FAILURE (icu_err))
+    return FALSE;
+  if (u_countChar32 (normalized, len) == 1) {
+    U16_GET_UNSAFE (normalized, 0, *ab);
+    ret = TRUE;
+  } else {
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
+static hb_bool_t
+hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+			  hb_codepoint_t      ab,
+			  hb_codepoint_t     *a,
+			  hb_codepoint_t     *b,
+			  void               *user_data HB_UNUSED)
+{
+  UChar utf16[2], normalized[20];
+  int len;
+  hb_bool_t ret, err;
+  UErrorCode icu_err;
+
+  /* This function is a monster! Maybe it wasn't a good idea adding a
+   * pairwise decompose API... */
+  /* Watchout for the dragons.  Err, watchout for macros changing len. */
+
+  len = 0;
+  err = FALSE;
+  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
+  if (err) return FALSE;
+
+  icu_err = U_ZERO_ERROR;
+  len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  if (U_FAILURE (icu_err))
+    return FALSE;
+
+  len = u_countChar32 (normalized, len);
+
+  if (len == 1) {
+    U16_GET_UNSAFE (normalized, 0, *a);
+    *b = 0;
+    ret = *a != ab;
+  } else if (len == 2) {
+    len =0;
+    U16_NEXT_UNSAFE (normalized, len, *a);
+    U16_NEXT_UNSAFE (normalized, len, *b);
+
+    /* Here's the ugly part: if ab decomposes to a single character and
+     * that character decomposes again, we have to detect that and undo
+     * the second part :-(. */
+    UChar recomposed[20];
+    icu_err = U_ZERO_ERROR;
+    unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
+    if (U_FAILURE (icu_err))
+      return FALSE;
+    hb_codepoint_t c;
+    U16_GET_UNSAFE (recomposed, 0, c);
+    if (c != *a && c != ab) {
+      *a = c;
+      *b = 0;
+    }
+    ret = TRUE;
+  } else {
+    /* If decomposed to more than two characters, take the last one,
+     * and recompose the rest to get the first component. */
+    U16_PREV_UNSAFE (normalized, len, *b);
+    UChar recomposed[20];
+    icu_err = U_ZERO_ERROR;
+    len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
+    if (U_FAILURE (icu_err))
+      return FALSE;
+    /* We expect that recomposed has exactly one character now. */
+    U16_GET_UNSAFE (recomposed, 0, *a);
+    ret = TRUE;
+  }
+
+  return ret;
+}
+
+extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_icu;
+hb_unicode_funcs_t _hb_icu_unicode_funcs = {
+  HB_OBJECT_HEADER_STATIC,
+
+  NULL, /* parent */
+  TRUE, /* immutable */
+  {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
+    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+  }
+};
+
+hb_unicode_funcs_t *
+hb_icu_get_unicode_funcs (void)
+{
+  return &_hb_icu_unicode_funcs;
+}
+
+
--- a/gfx/harfbuzz/src/hb-icu.h
+++ b/gfx/harfbuzz/src/hb-icu.h
@@ -1,10 +1,11 @@
 /*
- * Copyright (C) 2009  Red Hat, Inc.
+ * 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.
@@ -17,25 +18,35 @@
  *
  * 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_ICU_H
 #define HB_ICU_H
 
 #include "hb.h"
+#include <unicode/uscript.h>
+
 
 HB_BEGIN_DECLS
 
 
+hb_script_t
+hb_icu_script_to_script (UScriptCode script);
+
+UScriptCode
+hb_icu_script_from_script (hb_script_t script);
+
+
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void);
 
 
 HB_END_DECLS
 
 #endif /* HB_ICU_H */
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-language.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#include "hb-private.h"
-
-#include "hb-language.h"
-
-HB_BEGIN_DECLS
-
-
-static const char canon_map[256] = {
-   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
-   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
-   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
-  '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
-  '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
-   0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
-};
-
-static hb_bool_t
-lang_equal (const void *v1,
-	    const void *v2)
-{
-  const unsigned char *p1 = v1;
-  const unsigned char *p2 = v2;
-
-  while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
-    {
-      p1++, p2++;
-    }
-
-  return (canon_map[*p1] == canon_map[*p2]);
-}
-
-#if 0
-static unsigned int
-lang_hash (const void *key)
-{
-  const unsigned char *p = key;
-  unsigned int h = 0;
-  while (canon_map[*p])
-    {
-      h = (h << 5) - h + canon_map[*p];
-      p++;
-    }
-
-  return h;
-}
-#endif
-
-
-hb_language_t
-hb_language_from_string (const char *str)
-{
-  static unsigned int num_langs;
-  static unsigned int num_alloced;
-  static const char **langs;
-  unsigned int i;
-  unsigned char *p;
-
-  /* TODO Use a hash table or something */
-
-  if (!str)
-    return NULL;
-
-  for (i = 0; i < num_langs; i++)
-    if (lang_equal (str, langs[i]))
-      return langs[i];
-
-  if (unlikely (num_langs == num_alloced)) {
-    unsigned int new_alloced = 2 * (8 + num_alloced);
-    const char **new_langs = realloc (langs, new_alloced * sizeof (langs[0]));
-    if (!new_langs)
-      return NULL;
-    num_alloced = new_alloced;
-    langs = new_langs;
-  }
-
-  langs[i] = strdup (str);
-  for (p = (unsigned char *) langs[i]; *p; p++)
-    *p = canon_map[*p];
-
-  num_langs++;
-
-  return (hb_language_t) langs[i];
-}
-
-const char *
-hb_language_to_string (hb_language_t language)
-{
-  return (const char *) language;
-}
-
-
-HB_END_DECLS
deleted file mode 100644
--- a/gfx/harfbuzz/src/hb-language.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2009  Red Hat, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Red Hat Author(s): Behdad Esfahbod