bug 745780 - update harfbuzz code to upstream commit 3cde23664fbbe9cd2ac1b8fd5eb2ea288309cc9c (2012-04-17). r=jdaggett a=mfinkle
authorJonathan Kew <jkew@mozilla.com>
Sat, 21 Apr 2012 22:24:39 +0100
changeset 92086 03fa311b5a9badeb1866bcebd125a2c9d0342527
parent 92085 0d48034b460e9822a5e34aecdf26d27152408727
child 92087 25ca02ba36f4876505e565877296ae6b48ec140b
push id22504
push userphilringnalda@gmail.com
push dateSun, 22 Apr 2012 06:24:14 +0000
treeherdermozilla-central@990f6542747b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdaggett, mfinkle
bugs745780
milestone14.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 745780 - update harfbuzz code to upstream commit 3cde23664fbbe9cd2ac1b8fd5eb2ea288309cc9c (2012-04-17). r=jdaggett a=mfinkle
content/base/src/nsContentUtils.cpp
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/Makefile.in
gfx/harfbuzz/src/gen-arabic-table.py
gfx/harfbuzz/src/gen-indic-table.py
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.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.h
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-ft.h
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-glib.h
gfx/harfbuzz/src/hb-gobject-enums.cc
gfx/harfbuzz/src/hb-gobject.h
gfx/harfbuzz/src/hb-graphite2-private.hh
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-graphite2.h
gfx/harfbuzz/src/hb-icu.h
gfx/harfbuzz/src/hb-mutex-private.hh
gfx/harfbuzz/src/hb-object-private.hh
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-layout.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-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-tag.h
gfx/harfbuzz/src/hb-ot.h
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shape.h
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-unicode.cc
gfx/harfbuzz/src/hb-unicode.h
gfx/harfbuzz/src/hb-uniscribe-private.hh
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-warning.cc
gfx/harfbuzz/src/hb.h
gfx/thebes/gfxDWriteFonts.cpp
gfx/thebes/gfxFT2FontBase.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxGraphiteShaper.cpp
gfx/thebes/gfxHarfBuzzShaper.cpp
gfx/thebes/gfxPangoFonts.cpp
gfx/thebes/gfxPlatform.cpp
intl/unicharutil/util/nsUnicodePropertyData.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -117,17 +117,17 @@
 #include "nsIXTFService.h"
 static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
 #endif
 #include "nsIMIMEService.h"
 #include "nsLWBrkCIID.h"
 #include "nsILineBreaker.h"
 #include "nsIWordBreaker.h"
 #include "nsUnicodeProperties.h"
-#include "harfbuzz/hb-common.h"
+#include "harfbuzz/hb.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMDocumentXBL.h"
 #include "nsBindingManager.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsXBLBinding.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsEscape.h"
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -33,16 +33,17 @@ HBSOURCES =  \
 	hb-ot-maxp-table.hh \
 	hb-ot-name-table.hh \
 	hb-ot-tag.cc \
 	hb-private.hh \
 	hb-shape.cc \
 	hb-tt-font.cc \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
+	hb-warning.cc \
 	$(NULL)
 HBHEADERS = \
 	hb.h \
 	hb-blob.h \
 	hb-buffer.h \
 	hb-common.h \
 	hb-font.h \
 	hb-shape.h \
@@ -64,23 +65,23 @@ HBSOURCES += \
 	hb-ot-shape.cc \
 	hb-ot-shape-complex-arabic.cc \
 	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-private.hh \
 	hb-ot-shape-normalize.cc \
 	hb-ot-shape-private.hh \
 	$(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.cc
@@ -111,27 +112,27 @@ endif
 
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
 HBSOURCES += hb-ft.cc
 HBHEADERS += hb-ft.h
 endif
 
-if HAVE_GRAPHITE
-HBCFLAGS += $(GRAPHITE_CFLAGS)
-HBLIBS   += $(GRAPHITE_LIBS)
-HBSOURCES += hb-graphite2.cc
+if HAVE_GRAPHITE2
+HBCFLAGS += $(GRAPHITE2_CFLAGS)
+HBLIBS   += $(GRAPHITE2_LIBS)
+HBSOURCES += hb-graphite2.cc hb-graphite2-private.hh
 HBHEADERS += hb-graphite2.h
 endif
 
 if HAVE_UNISCRIBE
 HBCFLAGS += $(UNISCRIBE_CFLAGS)
 HBLIBS   += $(UNISCRIBE_LIBS)
-HBSOURCES += hb-uniscribe.cc
+HBSOURCES += hb-uniscribe.cc hb-uniscribe-private.hh
 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
@@ -142,16 +143,31 @@ nodist_pkginclude_HEADERS = hb-version.h
 
 GENERATORS = \
 	gen-arabic-table.py \
 	gen-indic-table.py \
 	$(NULL)
 
 EXTRA_DIST += $(GENERATORS)
 
+unicode-tables: arabic-table indic-table
+
+indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
+	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.hh.tmp && \
+	mv hb-ot-shape-complex-indic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-indic-table.hh || \
+	($(RM) hb-ot-shape-complex-indic-table.hh.tmp; false)
+
+arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
+	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
+	mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
+	($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
+
+
+.PHONY: unicode-tables arabic-table indic-table
+
 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 =
--- a/gfx/harfbuzz/src/Makefile.in
+++ b/gfx/harfbuzz/src/Makefile.in
@@ -47,16 +47,17 @@ CPPSRCS	=                        \
   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                  \
+  hb-warning.cc                  \
   $(NULL)
 
 EXPORTS_NAMESPACES = harfbuzz
 
 EXPORTS_harfbuzz = \
   hb.h             \
   hb-blob.h        \
   hb-buffer.h      \
@@ -74,13 +75,13 @@ EXPORTS_harfbuzz = \
 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
+DEFINES += -DHAVE_OT=1 -DHB_NO_MT
 
 # Cancel the effect of the -DDEBUG macro if present,
 # because harfbuzz uses that name for its own purposes
 COMPILE_CXXFLAGS += -UDEBUG
--- a/gfx/harfbuzz/src/gen-arabic-table.py
+++ b/gfx/harfbuzz/src/gen-arabic-table.py
@@ -1,88 +1,197 @@
 #!/usr/bin/python
 
 import sys
+import os.path
 
-if len (sys.argv) < 2:
-	print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt"
+if len (sys.argv) != 3:
+	print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
 	sys.exit (1)
 
-f = file (sys.argv[1])
+files = [file (x) for x in sys.argv[1:]]
+
+headers = [[files[0].readline (), files[0].readline ()]]
+headers.append (["UnicodeData.txt does not have a header."])
+while files[0].readline ().find ('##################') < 0:
+	pass
+
+
+def print_joining_table(f):
+
+	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
+
+	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)
+
+def print_shaping_table(f):
+
+	shapes = {}
+	ligatures = {}
+	names = {}
+	for line in f:
+
+		fields = [x.strip () for x in line.split (';')]
+		if fields[5][0:1] != '<':
+			continue
 
-header = f.readline (), f.readline ()
-while f.readline ().find ('##################') < 0:
-	pass
+		items = fields[5].split (' ')
+		shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:])
+
+		if not shape in ['initial', 'medial', 'isolated', 'final']:
+			continue
+
+		c = int (fields[0], 16)
+		if len (items) != 1:
+			# We only care about lam-alef ligatures
+			if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]:
+				continue
+
+			# Save ligature
+			names[c] = fields[1]
+			if items not in ligatures:
+				ligatures[items] = {}
+			ligatures[items][shape] = c
+			pass
+		else:
+			# Save shape
+			if items[0] not in names:
+				names[items[0]] = fields[1]
+			else:
+				names[items[0]] = os.path.commonprefix ([names[items[0]], fields[1]]).strip ()
+			if items[0] not in shapes:
+				shapes[items[0]] = {}
+			shapes[items[0]][shape] = c
+
+	print
+	print "static const uint16_t shaping_table[][4] ="
+	print "{"
+
+	keys = shapes.keys ()
+	min_u, max_u = min (keys), max (keys)
+	for u in range (min_u, max_u + 1):
+		s = [shapes[u][shape] if u in shapes and shape in shapes[u] else u
+		     for shape in  ['initial', 'medial', 'final', 'isolated']]
+		value = ', '.join ("0x%04X" % c for c in s)
+		print "  {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
+
+	print "};"
+	print
+	print "#define SHAPING_TABLE_FIRST	0x%04X" % min_u
+	print "#define SHAPING_TABLE_LAST	0x%04X" % max_u
+	print
+
+	ligas = {}
+	for pair in ligatures.keys ():
+		for shape in ligatures[pair]:
+			c = ligatures[pair][shape]
+			if shape == 'isolated':
+				liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final'])
+			elif shape == 'final':
+				liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final'])
+			else:
+				raise Exception ("Unexpected shape", shape)
+			if liga[0] not in ligas:
+				ligas[liga[0]] = []
+			ligas[liga[0]].append ((liga[1], c))
+	max_i = max (len (ligas[l]) for l in ligas)
+	print
+	print "static const struct {"
+	print " uint16_t first;"
+	print " struct {"
+	print "   uint16_t second;"
+	print "   uint16_t ligature;"
+	print " } ligatures[%d];" % max_i
+	print "} ligature_table[] ="
+	print "{"
+	keys = ligas.keys ()
+	keys.sort ()
+	for first in keys:
+
+		print "  { 0x%04X, {" % (first)
+		for liga in ligas[first]:
+			print "    { 0x%04X, 0x%04X }, /* %s */" % (liga[0], liga[1], names[liga[1]])
+		print "  }},"
+
+	print "};"
+	print
+
 
 
 print "/* == Start of generated table == */"
 print "/*"
 print " * The following table is generated by running:"
 print " *"
-print " *   ./gen-arabic-table.py ArabicShaping.txt"
+print " *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
 print " *"
 print " * on files with these headers:"
 print " *"
-for line in header:
-	print " * %s" % (line.strip())
+for h in headers:
+	for l in h:
+		print " * %s" % (l.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
+print
+print "#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
+print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
+print
 
-	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_joining_table (files[0])
+print_shaping_table (files[1])
 
 print
-print "};"
+print "#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */"
 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)
--- a/gfx/harfbuzz/src/gen-indic-table.py
+++ b/gfx/harfbuzz/src/gen-indic-table.py
@@ -1,17 +1,17 @@
 #!/usr/bin/python
 
 import sys
 
-if len (sys.argv) < 4:
+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)]
+files = [file (x) for x in sys.argv[1:]]
 
 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:
@@ -69,19 +69,22 @@ 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 " */"
+print
+print "#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
+print "#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
+print
 
 # Shorten values
-print
 short = [{
 	"Bindu":		'Bi',
 	"Visarga":		'Vs',
 	"Vowel":		'Vo',
 	"Vowel_Dependent":	'M',
 	"Other":		'x',
 },{
 	"Not_Applicable":	'x',
@@ -115,38 +118,35 @@ for i in range (2):
 			(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
 
+total = 0
+used = 0
 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)
+	global total, used
+	total += end - start + 1
+	used += num
 
 uu = data.keys ()
 uu.sort ()
 
 last = -1
 num = 0
 offset = 0
 starts = []
@@ -174,35 +174,38 @@ for u in uu:
 	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 "};"
-
+occupancy = used * 100. / total
+print "}; /* Table occupancy: %d%% */" % occupancy
 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 "#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */"
 print
 print "/* == End of generated table == */"
+
+# Maintain at least 30% occupancy in the table */
+if occupancy < 30:
+	raise Exception ("Table too sparse, please investigate: ", occupancy)
--- a/gfx/harfbuzz/src/hb-blob.cc
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -296,17 +296,17 @@ static bool
 
   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);
+  DEBUG_MSG_FUNC (BLOB, blob, "current 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);
--- a/gfx/harfbuzz/src/hb-blob.h
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -19,16 +19,20 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_BLOB_H
 #define HB_BLOB_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -126,16 +126,21 @@ struct _hb_buffer_t {
     for (unsigned int j = 0; j < len; j++)
       info[j].mask |= mask;
   }
   HB_INTERNAL void set_masks (hb_mask_t value,
 			      hb_mask_t mask,
 			      unsigned int cluster_start,
 			      unsigned int cluster_end);
 
+  HB_INTERNAL void merge_clusters (unsigned int start,
+				   unsigned int end);
+  HB_INTERNAL void merge_out_clusters (unsigned int start,
+				       unsigned int 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);
 
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -218,16 +218,17 @@ hb_buffer_t::clear_positions (void)
 }
 
 void
 hb_buffer_t::swap_buffers (void)
 {
   if (unlikely (in_error)) return;
 
   assert (have_output);
+  have_output = FALSE;
 
   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;
@@ -426,16 +427,39 @@ hb_buffer_t::reverse_clusters (void)
       start = i;
       last_cluster = info[i].cluster;
     }
   }
   reverse_range (start, i);
 }
 
 void
+hb_buffer_t::merge_clusters (unsigned int start,
+			     unsigned int end)
+{
+  unsigned int cluster = this->info[start].cluster;
+
+  for (unsigned int i = start + 1; i < end; i++)
+    cluster = MIN (cluster, this->info[i].cluster);
+  for (unsigned int i = start; i < end; i++)
+    this->info[i].cluster = cluster;
+}
+void
+hb_buffer_t::merge_out_clusters (unsigned int start,
+				 unsigned int end)
+{
+  unsigned int cluster = this->out_info[start].cluster;
+
+  for (unsigned int i = start + 1; i < end; i++)
+    cluster = MIN (cluster, this->out_info[i].cluster);
+  for (unsigned int i = start; i < end; i++)
+    this->out_info[i].cluster = cluster;
+}
+
+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 &&
--- a/gfx/harfbuzz/src/hb-buffer.h
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -22,16 +22,20 @@
  * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_BUFFER_H
 #define HB_BUFFER_H
 
 #include "hb-common.h"
 #include "hb-unicode.h"
 
 HB_BEGIN_DECLS
 
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -75,26 +75,27 @@ hb_direction_from_string (const char *st
     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_t) (HB_DIRECTION_LTR + 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];
+  if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
+	      < ARRAY_LENGTH (direction_strings)))
+    return direction_strings[direction - HB_DIRECTION_LTR];
 
   return "invalid";
 }
 
 
 /* hb_language_t */
 
 struct _hb_language_t {
@@ -259,42 +260,56 @@ 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)
 {
+  /* http://goo.gl/x9ilM */
   switch ((hb_tag_t) script)
   {
+    /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
     case HB_SCRIPT_HEBREW:
+
+    /* Unicode-3.0 additions */
     case HB_SCRIPT_SYRIAC:
     case HB_SCRIPT_THAANA:
 
     /* Unicode-4.0 additions */
     case HB_SCRIPT_CYPRIOT:
 
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_KHAROSHTHI:
+
     /* Unicode-5.0 additions */
     case HB_SCRIPT_PHOENICIAN:
     case HB_SCRIPT_NKO:
 
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_LYDIAN:
+
     /* 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:
 
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_MEROITIC_CURSIVE:
+    case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
+
       return HB_DIRECTION_RTL;
   }
 
   return HB_DIRECTION_LTR;
 }
 
 
 /* hb_user_data_array_t */
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -1,11 +1,11 @@
 /*
  * Copyright © 2007,2008,2009  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -21,16 +21,20 @@
  * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #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
@@ -84,49 +88,50 @@ typedef union _hb_var_int_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);
+/* len=-1 means str is NUL-terminated */
+hb_tag_t hb_tag_from_string (const char *str, int len);
 
 
 /* hb_direction_t */
 
 typedef enum {
-  HB_DIRECTION_INVALID = -1,
-  HB_DIRECTION_LTR = 0,
+  HB_DIRECTION_INVALID = 0,
+  HB_DIRECTION_LTR = 4,
   HB_DIRECTION_RTL,
   HB_DIRECTION_TTB,
   HB_DIRECTION_BTT
 } hb_direction_t;
 
-/* len=-1 means s is NUL-terminated */
+/* len=-1 means str 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))
+#define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 4)
+#define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 6)
+#define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 4)
+#define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 5)
+#define HB_DIRECTION_IS_VALID(dir)	((((unsigned int) (dir)) & ~3U) == 4)
+#define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */
 
 
 /* hb_language_t */
 
 typedef struct _hb_language_t *hb_language_t;
 
-/* len=-1 means s is NUL-terminated */
+/* len=-1 means str is NUL-terminated */
 hb_language_t
 hb_language_from_string (const char *str, int len);
 
 const char *
 hb_language_to_string (hb_language_t language);
 
 #define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
 
@@ -169,138 +174,148 @@ typedef enum
   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/ */
+/* http://goo.gl/x9ilM */
 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-1.1 additions */
+  HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
+  HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
+  HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'),
+  HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'),
+  HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'),
+  HB_SCRIPT_CANADIAN_ABORIGINAL		= HB_TAG ('C','a','n','s'),
+  HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'),
+  HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'),
+  HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'),
+  HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'),
+  HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'),
+  HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'),
+  HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'),
+  HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'),
+  HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'),
+  HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'),
+  HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'),
+  HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'),
+  HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
+  HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'),
+  HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'),
+  HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'),
+  HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'),
+  HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'),
+  HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'),
+  HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'),
+  HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'),
+  HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'),
+  HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'),
+  HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'),
+  HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'),
+  HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'),
+  HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'),
+
+  /* Unicode-2.0 additions */
+  HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'),
+
+  /* Unicode-3.0 additions */
+  HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'),
+  HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'),
+  HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'),
+  HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'),
+  HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'),
+
+  /* Unicode-3.1 additions */
+  HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'),
+  HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'),
+  HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'),
+
+  /* Unicode-3.2 additions */
+  HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'),
+  HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'),
+  HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'),
+  HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'),
 
   /* 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'),
+  HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'),
+  HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'),
+  HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'),
+  HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'),
+  HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'),
+  HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'),
+  HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'),
+  HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'),
 
   /* 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'),
+  HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'),
+  HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'),
+  HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'),
+  HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'),
+  HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'),
+  HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'),
+  HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'),
 
   /* 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'),
+  HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'),
+  HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'),
+  HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'),
+  HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'),
+  HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'),
+  HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),
 
   /* 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'),
+  HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'),
+  HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'),
+  HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'),
+  HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'),
+  HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'),
+  HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'),
+  HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'),
+  HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'),
+  HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'),
+  HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'),
+  HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'),
 
   /* 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'),
+  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'),
+  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'),
+  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_INVALID			= HB_TAG_NONE
 } hb_script_t;
 
 
 /* Script functions */
 
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
--- a/gfx/harfbuzz/src/hb-fallback-shape-private.hh
+++ b/gfx/harfbuzz/src/hb-fallback-shape-private.hh
@@ -31,18 +31,17 @@
 
 #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_fallback_shape (hb_font_t          *font,
+		    hb_buffer_t        *buffer,
+		    const hb_feature_t *features,
+		    unsigned int        num_features);
 
 
 HB_END_DECLS
 
 #endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-fallback-shape.cc
+++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
@@ -24,21 +24,20 @@
  * 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)
+_hb_fallback_shape (hb_font_t          *font,
+		    hb_buffer_t        *buffer,
+		    const hb_feature_t *features,
+		    unsigned int        num_features)
 {
   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);
 
--- a/gfx/harfbuzz/src/hb-font.h
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -19,16 +19,20 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_FONT_H
 #define HB_FONT_H
 
 #include "hb-common.h"
 #include "hb-blob.h"
 
 HB_BEGIN_DECLS
 
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -56,16 +56,18 @@
  *   - 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?
+ *
+ *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
  */
 
 
 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,
--- a/gfx/harfbuzz/src/hb-ft.h
+++ b/gfx/harfbuzz/src/hb-ft.h
@@ -24,18 +24,16 @@
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_FT_H
 #define HB_FT_H
 
 #include "hb.h"
 
-#include "hb-font.h"
-
 #include <ft2build.h>
 #include FT_FREETYPE_H
 
 HB_BEGIN_DECLS
 
 /* Note: FreeType is not thread-safe.  Hence, these functions are not either. */
 
 hb_face_t *
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -139,17 +139,26 @@ glib_script_to_script[] =
   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
+  HB_SCRIPT_MANDAIC,
+
+  /* Unicode-6.1 additions */
+  HB_SCRIPT_CHAKMA,
+  HB_SCRIPT_MEROITIC_CURSIVE,
+  HB_SCRIPT_MEROITIC_HIEROGLYPHS,
+  HB_SCRIPT_MIAO,
+  HB_SCRIPT_SHARADA,
+  HB_SCRIPT_SORA_SOMPENG,
+  HB_SCRIPT_TAKRI
 };
 #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);
--- a/gfx/harfbuzz/src/hb-glib.h
+++ b/gfx/harfbuzz/src/hb-glib.h
@@ -25,16 +25,17 @@
  * 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);
 
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-gobject-enums.cc
@@ -0,0 +1,266 @@
+
+/* Generated data (by glib-mkenums) */
+
+/*
+ * 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"
+
+/* enumerations from "../../src/hb-blob.h" */
+inline static /* TODO(behdad) disable these for now until we fix them... */
+GType
+hb_memory_mode_t_hb_memory_mode_t_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { HB_MEMORY_MODE_DUPLICATE, "HB_MEMORY_MODE_DUPLICATE", "duplicate" },
+        { HB_MEMORY_MODE_READONLY, "HB_MEMORY_MODE_READONLY", "readonly" },
+        { HB_MEMORY_MODE_WRITABLE, "HB_MEMORY_MODE_WRITABLE", "writable" },
+        { HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, "HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE", "readonly-may-make-writable" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("hb_memory_mode_t"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+/* enumerations from "../../src/hb-common.h" */
+inline static /* TODO(behdad) disable these for now until we fix them... */
+GType
+hb_direction_t_hb_direction_t_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { HB_DIRECTION_INVALID, "HB_DIRECTION_INVALID", "invalid" },
+        { HB_DIRECTION_LTR, "HB_DIRECTION_LTR", "ltr" },
+        { HB_DIRECTION_RTL, "HB_DIRECTION_RTL", "rtl" },
+        { HB_DIRECTION_TTB, "HB_DIRECTION_TTB", "ttb" },
+        { HB_DIRECTION_BTT, "HB_DIRECTION_BTT", "btt" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("hb_direction_t"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+inline static /* TODO(behdad) disable these for now until we fix them... */
+GType
+hb_unicode_general_category_t_hb_unicode_general_category_t_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { HB_UNICODE_GENERAL_CATEGORY_CONTROL, "HB_UNICODE_GENERAL_CATEGORY_CONTROL", "control" },
+        { HB_UNICODE_GENERAL_CATEGORY_FORMAT, "HB_UNICODE_GENERAL_CATEGORY_FORMAT", "format" },
+        { HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, "HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED", "unassigned" },
+        { HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, "HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE", "private-use" },
+        { HB_UNICODE_GENERAL_CATEGORY_SURROGATE, "HB_UNICODE_GENERAL_CATEGORY_SURROGATE", "surrogate" },
+        { HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER", "lowercase-letter" },
+        { HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER", "modifier-letter" },
+        { HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER", "other-letter" },
+        { HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER", "titlecase-letter" },
+        { HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER", "uppercase-letter" },
+        { HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK", "spacing-mark" },
+        { HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, "HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK", "enclosing-mark" },
+        { HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK", "non-spacing-mark" },
+        { HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER", "decimal-number" },
+        { HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER", "letter-number" },
+        { HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER", "other-number" },
+        { HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION", "connect-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION", "dash-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION", "close-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION", "final-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION", "initial-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION", "other-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION", "open-punctuation" },
+        { HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL", "currency-symbol" },
+        { HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL", "modifier-symbol" },
+        { HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL", "math-symbol" },
+        { HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL", "other-symbol" },
+        { HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR", "line-separator" },
+        { HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR", "paragraph-separator" },
+        { HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR", "space-separator" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("hb_unicode_general_category_t"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+inline static /* TODO(behdad) disable these for now until we fix them... */
+GType
+hb_script_t_hb_script_t_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      static const GEnumValue values[] = {
+        { HB_SCRIPT_COMMON, "HB_SCRIPT_COMMON", "common" },
+        { HB_SCRIPT_ARABIC, "HB_SCRIPT_ARABIC", "arabic" },
+        { HB_SCRIPT_ARMENIAN, "HB_SCRIPT_ARMENIAN", "armenian" },
+        { HB_SCRIPT_BENGALI, "HB_SCRIPT_BENGALI", "bengali" },
+        { HB_SCRIPT_BOPOMOFO, "HB_SCRIPT_BOPOMOFO", "bopomofo" },
+        { HB_SCRIPT_CANADIAN_ABORIGINAL, "HB_SCRIPT_CANADIAN_ABORIGINAL", "canadian-aboriginal" },
+        { HB_SCRIPT_CHEROKEE, "HB_SCRIPT_CHEROKEE", "cherokee" },
+        { HB_SCRIPT_COPTIC, "HB_SCRIPT_COPTIC", "coptic" },
+        { HB_SCRIPT_CYRILLIC, "HB_SCRIPT_CYRILLIC", "cyrillic" },
+        { HB_SCRIPT_DEVANAGARI, "HB_SCRIPT_DEVANAGARI", "devanagari" },
+        { HB_SCRIPT_GEORGIAN, "HB_SCRIPT_GEORGIAN", "georgian" },
+        { HB_SCRIPT_GREEK, "HB_SCRIPT_GREEK", "greek" },
+        { HB_SCRIPT_GUJARATI, "HB_SCRIPT_GUJARATI", "gujarati" },
+        { HB_SCRIPT_GURMUKHI, "HB_SCRIPT_GURMUKHI", "gurmukhi" },
+        { HB_SCRIPT_HANGUL, "HB_SCRIPT_HANGUL", "hangul" },
+        { HB_SCRIPT_HAN, "HB_SCRIPT_HAN", "han" },
+        { HB_SCRIPT_HEBREW, "HB_SCRIPT_HEBREW", "hebrew" },
+        { HB_SCRIPT_HIRAGANA, "HB_SCRIPT_HIRAGANA", "hiragana" },
+        { HB_SCRIPT_INHERITED, "HB_SCRIPT_INHERITED", "inherited" },
+        { HB_SCRIPT_KANNADA, "HB_SCRIPT_KANNADA", "kannada" },
+        { HB_SCRIPT_KATAKANA, "HB_SCRIPT_KATAKANA", "katakana" },
+        { HB_SCRIPT_LAO, "HB_SCRIPT_LAO", "lao" },
+        { HB_SCRIPT_LATIN, "HB_SCRIPT_LATIN", "latin" },
+        { HB_SCRIPT_MALAYALAM, "HB_SCRIPT_MALAYALAM", "malayalam" },
+        { HB_SCRIPT_MONGOLIAN, "HB_SCRIPT_MONGOLIAN", "mongolian" },
+        { HB_SCRIPT_OGHAM, "HB_SCRIPT_OGHAM", "ogham" },
+        { HB_SCRIPT_ORIYA, "HB_SCRIPT_ORIYA", "oriya" },
+        { HB_SCRIPT_RUNIC, "HB_SCRIPT_RUNIC", "runic" },
+        { HB_SCRIPT_SYRIAC, "HB_SCRIPT_SYRIAC", "syriac" },
+        { HB_SCRIPT_TAMIL, "HB_SCRIPT_TAMIL", "tamil" },
+        { HB_SCRIPT_TELUGU, "HB_SCRIPT_TELUGU", "telugu" },
+        { HB_SCRIPT_THAI, "HB_SCRIPT_THAI", "thai" },
+        { HB_SCRIPT_YI, "HB_SCRIPT_YI", "yi" },
+        { HB_SCRIPT_TIBETAN, "HB_SCRIPT_TIBETAN", "tibetan" },
+        { HB_SCRIPT_ETHIOPIC, "HB_SCRIPT_ETHIOPIC", "ethiopic" },
+        { HB_SCRIPT_KHMER, "HB_SCRIPT_KHMER", "khmer" },
+        { HB_SCRIPT_MYANMAR, "HB_SCRIPT_MYANMAR", "myanmar" },
+        { HB_SCRIPT_SINHALA, "HB_SCRIPT_SINHALA", "sinhala" },
+        { HB_SCRIPT_THAANA, "HB_SCRIPT_THAANA", "thaana" },
+        { HB_SCRIPT_DESERET, "HB_SCRIPT_DESERET", "deseret" },
+        { HB_SCRIPT_GOTHIC, "HB_SCRIPT_GOTHIC", "gothic" },
+        { HB_SCRIPT_OLD_ITALIC, "HB_SCRIPT_OLD_ITALIC", "old-italic" },
+        { HB_SCRIPT_BUHID, "HB_SCRIPT_BUHID", "buhid" },
+        { HB_SCRIPT_HANUNOO, "HB_SCRIPT_HANUNOO", "hanunoo" },
+        { HB_SCRIPT_TAGALOG, "HB_SCRIPT_TAGALOG", "tagalog" },
+        { HB_SCRIPT_TAGBANWA, "HB_SCRIPT_TAGBANWA", "tagbanwa" },
+        { HB_SCRIPT_BRAILLE, "HB_SCRIPT_BRAILLE", "braille" },
+        { HB_SCRIPT_CYPRIOT, "HB_SCRIPT_CYPRIOT", "cypriot" },
+        { HB_SCRIPT_LIMBU, "HB_SCRIPT_LIMBU", "limbu" },
+        { HB_SCRIPT_LINEAR_B, "HB_SCRIPT_LINEAR_B", "linear-b" },
+        { HB_SCRIPT_OSMANYA, "HB_SCRIPT_OSMANYA", "osmanya" },
+        { HB_SCRIPT_SHAVIAN, "HB_SCRIPT_SHAVIAN", "shavian" },
+        { HB_SCRIPT_TAI_LE, "HB_SCRIPT_TAI_LE", "tai-le" },
+        { HB_SCRIPT_UGARITIC, "HB_SCRIPT_UGARITIC", "ugaritic" },
+        { HB_SCRIPT_BUGINESE, "HB_SCRIPT_BUGINESE", "buginese" },
+        { HB_SCRIPT_GLAGOLITIC, "HB_SCRIPT_GLAGOLITIC", "glagolitic" },
+        { HB_SCRIPT_KHAROSHTHI, "HB_SCRIPT_KHAROSHTHI", "kharoshthi" },
+        { HB_SCRIPT_NEW_TAI_LUE, "HB_SCRIPT_NEW_TAI_LUE", "new-tai-lue" },
+        { HB_SCRIPT_OLD_PERSIAN, "HB_SCRIPT_OLD_PERSIAN", "old-persian" },
+        { HB_SCRIPT_SYLOTI_NAGRI, "HB_SCRIPT_SYLOTI_NAGRI", "syloti-nagri" },
+        { HB_SCRIPT_TIFINAGH, "HB_SCRIPT_TIFINAGH", "tifinagh" },
+        { HB_SCRIPT_BALINESE, "HB_SCRIPT_BALINESE", "balinese" },
+        { HB_SCRIPT_CUNEIFORM, "HB_SCRIPT_CUNEIFORM", "cuneiform" },
+        { HB_SCRIPT_NKO, "HB_SCRIPT_NKO", "nko" },
+        { HB_SCRIPT_PHAGS_PA, "HB_SCRIPT_PHAGS_PA", "phags-pa" },
+        { HB_SCRIPT_PHOENICIAN, "HB_SCRIPT_PHOENICIAN", "phoenician" },
+        { HB_SCRIPT_UNKNOWN, "HB_SCRIPT_UNKNOWN", "unknown" },
+        { HB_SCRIPT_CARIAN, "HB_SCRIPT_CARIAN", "carian" },
+        { HB_SCRIPT_CHAM, "HB_SCRIPT_CHAM", "cham" },
+        { HB_SCRIPT_KAYAH_LI, "HB_SCRIPT_KAYAH_LI", "kayah-li" },
+        { HB_SCRIPT_LEPCHA, "HB_SCRIPT_LEPCHA", "lepcha" },
+        { HB_SCRIPT_LYCIAN, "HB_SCRIPT_LYCIAN", "lycian" },
+        { HB_SCRIPT_LYDIAN, "HB_SCRIPT_LYDIAN", "lydian" },
+        { HB_SCRIPT_OL_CHIKI, "HB_SCRIPT_OL_CHIKI", "ol-chiki" },
+        { HB_SCRIPT_REJANG, "HB_SCRIPT_REJANG", "rejang" },
+        { HB_SCRIPT_SAURASHTRA, "HB_SCRIPT_SAURASHTRA", "saurashtra" },
+        { HB_SCRIPT_SUNDANESE, "HB_SCRIPT_SUNDANESE", "sundanese" },
+        { HB_SCRIPT_VAI, "HB_SCRIPT_VAI", "vai" },
+        { HB_SCRIPT_AVESTAN, "HB_SCRIPT_AVESTAN", "avestan" },
+        { HB_SCRIPT_BAMUM, "HB_SCRIPT_BAMUM", "bamum" },
+        { HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, "HB_SCRIPT_EGYPTIAN_HIEROGLYPHS", "egyptian-hieroglyphs" },
+        { HB_SCRIPT_IMPERIAL_ARAMAIC, "HB_SCRIPT_IMPERIAL_ARAMAIC", "imperial-aramaic" },
+        { HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, "HB_SCRIPT_INSCRIPTIONAL_PAHLAVI", "inscriptional-pahlavi" },
+        { HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, "HB_SCRIPT_INSCRIPTIONAL_PARTHIAN", "inscriptional-parthian" },
+        { HB_SCRIPT_JAVANESE, "HB_SCRIPT_JAVANESE", "javanese" },
+        { HB_SCRIPT_KAITHI, "HB_SCRIPT_KAITHI", "kaithi" },
+        { HB_SCRIPT_LISU, "HB_SCRIPT_LISU", "lisu" },
+        { HB_SCRIPT_MEETEI_MAYEK, "HB_SCRIPT_MEETEI_MAYEK", "meetei-mayek" },
+        { HB_SCRIPT_OLD_SOUTH_ARABIAN, "HB_SCRIPT_OLD_SOUTH_ARABIAN", "old-south-arabian" },
+        { HB_SCRIPT_OLD_TURKIC, "HB_SCRIPT_OLD_TURKIC", "old-turkic" },
+        { HB_SCRIPT_SAMARITAN, "HB_SCRIPT_SAMARITAN", "samaritan" },
+        { HB_SCRIPT_TAI_THAM, "HB_SCRIPT_TAI_THAM", "tai-tham" },
+        { HB_SCRIPT_TAI_VIET, "HB_SCRIPT_TAI_VIET", "tai-viet" },
+        { HB_SCRIPT_BATAK, "HB_SCRIPT_BATAK", "batak" },
+        { HB_SCRIPT_BRAHMI, "HB_SCRIPT_BRAHMI", "brahmi" },
+        { HB_SCRIPT_MANDAIC, "HB_SCRIPT_MANDAIC", "mandaic" },
+        { HB_SCRIPT_CHAKMA, "HB_SCRIPT_CHAKMA", "chakma" },
+        { HB_SCRIPT_MEROITIC_CURSIVE, "HB_SCRIPT_MEROITIC_CURSIVE", "meroitic-cursive" },
+        { HB_SCRIPT_MEROITIC_HIEROGLYPHS, "HB_SCRIPT_MEROITIC_HIEROGLYPHS", "meroitic-hieroglyphs" },
+        { HB_SCRIPT_MIAO, "HB_SCRIPT_MIAO", "miao" },
+        { HB_SCRIPT_SHARADA, "HB_SCRIPT_SHARADA", "sharada" },
+        { HB_SCRIPT_SORA_SOMPENG, "HB_SCRIPT_SORA_SOMPENG", "sora-sompeng" },
+        { HB_SCRIPT_TAKRI, "HB_SCRIPT_TAKRI", "takri" },
+        { HB_SCRIPT_INVALID, "HB_SCRIPT_INVALID", "invalid" },
+        { 0, NULL, NULL }
+      };
+      GType g_define_type_id =
+        g_enum_register_static (g_intern_static_string ("hb_script_t"), values);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+
+  return g_define_type_id__volatile;
+}
+
+
+/* Generated data ends here */
+
--- a/gfx/harfbuzz/src/hb-gobject.h
+++ b/gfx/harfbuzz/src/hb-gobject.h
@@ -23,16 +23,17 @@
  *
  * 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 ()
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-graphite2-private.hh
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_GRAPHITE2_PRIVATE_HH
+#define HB_GRAPHITE2_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-graphite2.h"
+
+
+HB_INTERNAL hb_bool_t
+_hb_graphite2_shape (hb_font_t          *font,
+		     hb_buffer_t        *buffer,
+		     const hb_feature_t *features,
+		     unsigned int        num_features);
+
+
+#endif /* HB_GRAPHITE2_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -125,16 +125,17 @@ static void _hb_gr_face_data_destroy (vo
   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);
+  free (f);
 }
 
 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);
@@ -207,25 +208,27 @@ static hb_gr_font_data_t *
       return &_hb_gr_font_data_nil;
   }
 
   return data;
 }
 
 
 hb_bool_t
-hb_graphite_shape (hb_font_t          *font,
+_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)
+		   unsigned int        num_features)
 {
 
   buffer->guess_properties ();
 
+  /* XXX We do a hell of a lot of stuff just to figure out this font
+   * is not graphite!  Shouldn't do. */
+
   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;
 
--- a/gfx/harfbuzz/src/hb-graphite2.h
+++ b/gfx/harfbuzz/src/hb-graphite2.h
@@ -21,26 +21,20 @@
  * 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"
+#include "hb.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);
+/* TODO add gr_font/face etc getters and other glue API */
 
 HB_END_DECLS
 
 #endif /* HB_GRAPHITE2_H */
--- a/gfx/harfbuzz/src/hb-icu.h
+++ b/gfx/harfbuzz/src/hb-icu.h
@@ -25,16 +25,17 @@
  * 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);
--- a/gfx/harfbuzz/src/hb-mutex-private.hh
+++ b/gfx/harfbuzz/src/hb-mutex-private.hh
@@ -35,52 +35,56 @@
 #include "hb-private.hh"
 
 
 
 /* mutex */
 
 /* We need external help for these */
 
-#ifdef HAVE_GLIB
+#if !defined(HB_NO_MT) && defined(HAVE_GLIB)
 
 #include <glib.h>
-
 typedef GStaticMutex hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	G_STATIC_MUTEX_INIT
 #define hb_mutex_impl_init(M)	g_static_mutex_init (M)
 #define hb_mutex_impl_lock(M)	g_static_mutex_lock (M)
 #define hb_mutex_impl_unlock(M)	g_static_mutex_unlock (M)
 #define hb_mutex_impl_free(M)	g_static_mutex_free (M)
 
-
-#elif defined(_MSC_VER) || defined(__MINGW32__)
+#elif !defined(HB_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
 
 #include <windows.h>
-
 typedef CRITICAL_SECTION hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	{ NULL, 0, 0, NULL, NULL, 0 }
 #define hb_mutex_impl_init(M)	InitializeCriticalSection (M)
 #define hb_mutex_impl_lock(M)	EnterCriticalSection (M)
 #define hb_mutex_impl_unlock(M)	LeaveCriticalSection (M)
 #define hb_mutex_impl_free(M)	DeleteCriticalSection (M)
 
+#elif !defined(HB_NO_MT) && defined(__APPLE__)
+
+#include <pthread.h>
+typedef pthread_mutex_t hb_mutex_impl_t;
+#define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
+#define hb_mutex_impl_init(M)	pthread_mutex_init (M, NULL)
+#define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
+#define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
+#define hb_mutex_impl_free(M)	pthread_mutex_destroy (M)
 
 #else
 
-#warning "Could not find any system to define platform macros, library will NOT be thread-safe"
-
+#define HB_MUTEX_IMPL_NIL 1
 typedef volatile int hb_mutex_impl_t;
 #define HB_MUTEX_IMPL_INIT	0
 #define hb_mutex_impl_init(M)	((void) (*(M) = 0))
 #define hb_mutex_impl_lock(M)	((void) (*(M) = 1))
 #define hb_mutex_impl_unlock(M)	((void) (*(M) = 0))
 #define hb_mutex_impl_free(M)	((void) (*(M) = 2))
 
-
 #endif
 
 
 struct hb_mutex_t
 {
   hb_mutex_impl_t m;
 
   inline void init   (void) { hb_mutex_impl_init   (&m); }
--- a/gfx/harfbuzz/src/hb-object-private.hh
+++ b/gfx/harfbuzz/src/hb-object-private.hh
@@ -44,53 +44,49 @@
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
 
 
 /* atomic_int */
 
 /* We need external help for these */
 
-#ifdef HAVE_GLIB
+#if !defined(HB_NO_MT) && defined(HAVE_GLIB)
 
 #include <glib.h>
-
 typedef volatile int hb_atomic_int_t;
 #if GLIB_CHECK_VERSION(2,29,5)
 #define hb_atomic_int_add(AI, V)	g_atomic_int_add (&(AI), V)
 #else
 #define hb_atomic_int_add(AI, V)	g_atomic_int_exchange_and_add (&(AI), V)
 #endif
 #define hb_atomic_int_get(AI)		g_atomic_int_get (&(AI))
-#define hb_atomic_int_set(AI, V)	g_atomic_int_set (&(AI), V)
 
 
-#elif defined(_MSC_VER) && _MSC_VER >= 1600
+#elif !defined(HB_NO_MT) && defined(_MSC_VER) && _MSC_VER >= 1600
 
 #include <intrin.h>
-
 typedef long hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)	_InterlockedExchangeAdd (&(AI), V)
 #define hb_atomic_int_get(AI)		(_ReadBarrier (), (AI))
-#define hb_atomic_int_set(AI, V)	((void) _InterlockedExchange (&(AI), (V)))
+
+#elif !defined(HB_NO_MT) && defined(__APPLE__)
 
+#include <libkern/OSAtomic.h>
+typedef int32_t hb_atomic_int_t;
+#define hb_atomic_int_add(AI, V)	(OSAtomicAdd32Barrier((V), &(AI)), (AI) - (V))
+#define hb_atomic_int_get(AI)		OSAtomicAdd32Barrier(0, &(AI))
 
 #else
 
-#ifdef _MSC_VER
-#pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe")
-#else
-#warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe"
-#endif
+#define HB_ATOMIC_INT_NIL 1
 
 typedef volatile int hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)	((AI) += (V), (AI) - (V))
 #define hb_atomic_int_get(AI)		(AI)
-#define hb_atomic_int_set(AI, V)	((void) ((AI) = (V)))
-
 
 #endif
 
 
 
 
 /* reference_count */
 
@@ -98,20 +94,20 @@ typedef struct {
   hb_atomic_int_t ref_count;
 
 #define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1)
 #define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE}
 
   inline void init (int v) { ref_count = v; /* non-atomic is fine */ }
   inline int inc (void) { return hb_atomic_int_add (ref_count,  1); }
   inline int dec (void) { return hb_atomic_int_add (ref_count, -1); }
-  inline void set (int v) { hb_atomic_int_set (ref_count, v); }
 
-  inline int get (void) const { return hb_atomic_int_get (ref_count); }
-  inline bool is_invalid (void) const { return get () == HB_REFERENCE_COUNT_INVALID_VALUE; }
+  inline int get (void) { return hb_atomic_int_get (ref_count); }
+  inline int get_unsafe (void) const { return ref_count; }
+  inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; }
 
 } hb_reference_count_t;
 
 
 /* user_data */
 
 struct hb_user_data_array_t {
 
@@ -197,17 +193,17 @@ struct _hb_object_header_t {
 
   inline void *get_user_data (hb_user_data_key_t *key) {
     return user_data.get (key);
   }
 
   inline void trace (const char *function) const {
     DEBUG_MSG (OBJECT, (void *) this,
 	       "refcount=%d %s",
-	       this ? ref_count.get () : 0,
+	       this ? ref_count.get_unsafe () : 0,
 	       function);
   }
 
 };
 
 
 
 
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -25,17 +25,16 @@
  * Red Hat Author(s): Behdad Esfahbod
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
 
 #include "hb-ot-layout-private.hh"
-
 #include "hb-open-type-private.hh"
 
 
 #define NO_CONTEXT		((unsigned int) 0x110000)
 #define NOT_COVERED		((unsigned int) 0x110000)
 #define MAX_NESTING_LEVEL	8
 
 
@@ -267,17 +266,17 @@ struct Feature
   DEFINE_SIZE_ARRAY (4, lookupIndex);
 };
 
 typedef RecordListOf<Feature> FeatureList;
 
 
 struct LookupFlag : USHORT
 {
-  enum {
+  enum Flags {
     RightToLeft		= 0x0001u,
     IgnoreBaseGlyphs	= 0x0002u,
     IgnoreLigatures	= 0x0004u,
     IgnoreMarks		= 0x0008u,
     IgnoreFlags		= 0x000Eu,
     UseMarkFilteringSet	= 0x0010u,
     Reserved		= 0x00E0u,
     MarkAttachmentType	= 0xFF00u
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
@@ -322,17 +322,17 @@ struct MarkGlyphSets
 /*
  * GDEF -- The Glyph Definition Table
  */
 
 struct GDEF
 {
   static const hb_tag_t Tag	= HB_OT_TAG_GDEF;
 
-  enum {
+  enum GlyphClasses {
     UnclassifiedGlyph	= 0,
     BaseGlyph		= 1,
     LigatureGlyph	= 2,
     MarkGlyph		= 3,
     ComponentGlyph	= 4
   };
 
   inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
@@ -41,18 +41,17 @@
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
 
 typedef USHORT Value;
 
 typedef Value ValueRecord[VAR];
 
 struct ValueFormat : USHORT
 {
-  enum
-  {
+  enum Flags {
     xPlacement	= 0x0001,	/* Includes horizontal adjustment for placement */
     yPlacement	= 0x0002,	/* Includes vertical adjustment for placement */
     xAdvance	= 0x0004,	/* Includes horizontal adjustment for advance */
     yAdvance	= 0x0008,	/* Includes vertical adjustment for advance */
     xPlaDevice	= 0x0010,	/* Includes horizontal Device table for placement */
     yPlaDevice	= 0x0020,	/* Includes vertical Device table for placement */
     xAdvDevice	= 0x0040,	/* Includes horizontal Device table for advance */
     yAdvDevice	= 0x0080,	/* Includes vertical Device table for advance */
@@ -1331,17 +1330,17 @@ struct ExtensionPos : Extension
  * PosLookup
  */
 
 
 struct PosLookupSubTable
 {
   friend struct PosLookup;
 
-  enum {
+  enum Type {
     Single		= 1,
     Pair		= 2,
     Cursive		= 3,
     MarkBase		= 4,
     MarkLig		= 5,
     MarkMark		= 6,
     Context		= 7,
     ChainContext	= 8,
@@ -1399,33 +1398,19 @@ struct PosLookupSubTable
 };
 
 
 struct PosLookup : Lookup
 {
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
   { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
 
-  inline bool apply_once (hb_font_t *font,
-			  hb_buffer_t *buffer,
-			  hb_mask_t lookup_mask,
-			  unsigned int context_length,
-			  unsigned int nesting_level_left) const
+  inline bool apply_once (hb_apply_context_t *c) const
   {
     unsigned int lookup_type = get_type ();
-    hb_apply_context_t c[1] = {{0}};
-
-    c->font = font;
-    c->face = font->face;
-    c->buffer = buffer;
-    c->direction = buffer->props.direction;
-    c->lookup_mask = lookup_mask;
-    c->context_length = context_length;
-    c->nesting_level_left = nesting_level_left;
-    c->lookup_props = get_props ();
 
     if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
       return false;
 
     for (unsigned int i = 0; i < get_subtable_count (); i++)
       if (get_subtable (i).apply (c, lookup_type))
 	return true;
 
@@ -1436,21 +1421,22 @@ struct PosLookup : Lookup
 			     hb_buffer_t *buffer,
 			     hb_mask_t    mask) const
   {
     bool ret = false;
 
     if (unlikely (!buffer->len))
       return false;
 
+    hb_apply_context_t c (font, font->face, buffer, mask, *this);
+
     buffer->idx = 0;
     while (buffer->idx < buffer->len)
     {
-      if ((buffer->info[buffer->idx].mask & mask) &&
-	  apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+      if ((buffer->info[buffer->idx].mask & mask) && apply_once (&c))
 	ret = true;
       else
 	buffer->idx++;
     }
 
     return ret;
   }
 
@@ -1593,17 +1579,18 @@ static inline bool position_lookup (hb_a
   const PosLookup &l = gpos.get_lookup (lookup_index);
 
   if (unlikely (c->nesting_level_left == 0))
     return false;
 
   if (unlikely (c->context_length < 1))
     return false;
 
-  return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
+  hb_apply_context_t new_c (*c, l);
+  return l.apply_once (&new_c);
 }
 
 
 #undef attach_lookback
 #undef cursive_chain
 
 
 
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
@@ -673,17 +673,17 @@ struct ReverseChainSingleSubst
 /*
  * SubstLookup
  */
 
 struct SubstLookupSubTable
 {
   friend struct SubstLookup;
 
-  enum {
+  enum Type {
     Single		= 1,
     Multiple		= 2,
     Alternate		= 3,
     Ligature		= 4,
     Context		= 5,
     ChainContext	= 6,
     Extension		= 7,
     ReverseChainSingle	= 8
@@ -749,32 +749,19 @@ struct SubstLookup : Lookup
   {
     unsigned int type = get_type ();
     if (unlikely (type == SubstLookupSubTable::Extension))
       return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
     return lookup_type_is_reverse (type);
   }
 
 
-  inline bool apply_once (hb_face_t *face,
-			  hb_buffer_t *buffer,
-			  hb_mask_t lookup_mask,
-			  unsigned int context_length,
-			  unsigned int nesting_level_left) const
+  inline bool apply_once (hb_apply_context_t *c) const
   {
     unsigned int lookup_type = get_type ();
-    hb_apply_context_t c[1] = {{0}};
-
-    c->face = face;
-    c->buffer = buffer;
-    c->direction = buffer->props.direction;
-    c->lookup_mask = lookup_mask;
-    c->context_length = context_length;
-    c->nesting_level_left = nesting_level_left;
-    c->lookup_props = get_props ();
 
     if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
       return false;
 
     if (unlikely (lookup_type == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables should have the same type.
        * This is specially important if one has a reverse type!
@@ -800,41 +787,41 @@ struct SubstLookup : Lookup
 			    hb_buffer_t *buffer,
 			    hb_mask_t    mask) const
   {
     bool ret = false;
 
     if (unlikely (!buffer->len))
       return false;
 
+    hb_apply_context_t c (NULL, face, buffer, mask, *this);
+
     if (likely (!is_reverse ()))
     {
 	/* in/out forward substitution */
 	buffer->clear_output ();
 	buffer->idx = 0;
 	while (buffer->idx < buffer->len)
 	{
-	  if ((buffer->info[buffer->idx].mask & mask) &&
-	      apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+	  if ((buffer->info[buffer->idx].mask & mask) && apply_once (&c))
 	    ret = true;
 	  else
 	    buffer->next_glyph ();
 
 	}
 	if (ret)
 	  buffer->swap_buffers ();
     }
     else
     {
 	/* in-place backward substitution */
 	buffer->idx = buffer->len - 1;
 	do
 	{
-	  if ((buffer->info[buffer->idx].mask & mask) &&
-	      apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+	  if ((buffer->info[buffer->idx].mask & mask) && apply_once (&c))
 	    ret = true;
 	  else
 	    buffer->idx--;
 
 	}
 	while ((int) buffer->idx >= 0);
     }
 
@@ -931,14 +918,15 @@ static inline bool substitute_lookup (hb
   const SubstLookup &l = gsub.get_lookup (lookup_index);
 
   if (unlikely (c->nesting_level_left == 0))
     return false;
 
   if (unlikely (c->context_length < 1))
     return false;
 
-  return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
+  hb_apply_context_t new_c (*c, l);
+  return l.apply_once (&new_c);
 }
 
 
 
 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -62,16 +62,38 @@ struct hb_apply_context_t
   hb_buffer_t *buffer;
   hb_direction_t direction;
   hb_mask_t lookup_mask;
   unsigned int context_length;
   unsigned int nesting_level_left;
   unsigned int lookup_props;
   unsigned int property; /* propety of first glyph */
 
+
+  hb_apply_context_t (hb_font_t *font_,
+		      hb_face_t *face_,
+		      hb_buffer_t *buffer_,
+		      hb_mask_t lookup_mask_,
+		      const Lookup &l,
+		      unsigned int context_length_ = NO_CONTEXT,
+		      unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+			font (font_), face (face_), buffer (buffer_),
+			direction (buffer_->props.direction),
+			lookup_mask (lookup_mask_),
+			context_length (context_length_),
+			nesting_level_left (nesting_level_left_),
+			lookup_props (l.get_props ()),
+			property (0) {}
+
+  hb_apply_context_t (const hb_apply_context_t &c, const Lookup &l) {
+    *this = c;
+    nesting_level_left--;
+    lookup_props = l.get_props ();
+  }
+
   struct mark_skipping_forward_iterator_t
   {
     inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
 					     unsigned int start_index_,
 					     unsigned int num_items_)
     {
       c = c_;
       idx = start_index_;
--- a/gfx/harfbuzz/src/hb-ot-layout.cc
+++ b/gfx/harfbuzz/src/hb-ot-layout.cc
@@ -27,17 +27,16 @@
  */
 
 #include "hb-ot-layout-private.hh"
 
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
 #include "hb-ot-maxp-table.hh"
-#include "hb-ot-shape-private.hh"
 
 
 #include <stdlib.h>
 #include <string.h>
 
 
 
 hb_ot_layout_t *
@@ -492,52 +491,14 @@ hb_ot_layout_position_lookup   (hb_font_
 				hb_buffer_t  *buffer,
 				unsigned int  lookup_index,
 				hb_mask_t     mask)
 {
   return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask);
 }
 
 void
-hb_ot_layout_position_finish (hb_face_t *face, hb_buffer_t *buffer)
+hb_ot_layout_position_finish (hb_buffer_t  *buffer)
 {
-  /* force diacritics to have zero width */
-  unsigned int count = buffer->len;
-  if (hb_ot_layout_has_glyph_classes (face)) {
-    const GDEF& gdef = _get_gdef (face);
-    if (buffer->props.direction == HB_DIRECTION_RTL) {
-      for (unsigned int i = 1; i < count; i++) {
-        if (gdef.get_glyph_class (buffer->info[i].codepoint) == GDEF::MarkGlyph) {
-          buffer->pos[i].x_advance = 0;
-        }
-      }
-    } else {
-      for (unsigned int i = 1; i < count; i++) {
-        if (gdef.get_glyph_class (buffer->info[i].codepoint) == GDEF::MarkGlyph) {
-          hb_glyph_position_t& pos = buffer->pos[i];
-          pos.x_offset -= pos.x_advance;
-          pos.x_advance = 0;
-        }
-      }
-    }
-  } else {
-    /* no GDEF classes available, so use General Category as a fallback */
-    if (buffer->props.direction == HB_DIRECTION_RTL) {
-      for (unsigned int i = 1; i < count; i++) {
-        if (buffer->info[i].general_category() == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
-          buffer->pos[i].x_advance = 0;
-        }
-      }
-    } else {
-      for (unsigned int i = 1; i < count; i++) {
-        if (buffer->info[i].general_category() == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
-          hb_glyph_position_t& pos = buffer->pos[i];
-          pos.x_offset -= pos.x_advance;
-          pos.x_advance = 0;
-        }
-      }
-    }
-  }
-
   GPOS::position_finish (buffer);
 }
 
 
--- a/gfx/harfbuzz/src/hb-ot-layout.h
+++ b/gfx/harfbuzz/src/hb-ot-layout.h
@@ -19,22 +19,24 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
 #ifndef HB_OT_LAYOUT_H
 #define HB_OT_LAYOUT_H
 
-#include "hb-common.h"
-#include "hb-buffer.h"
-#include "hb-font.h"
+#include "hb.h"
 
 #include "hb-ot-tag.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
 #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
@@ -194,14 +196,14 @@ hb_ot_layout_position_start (hb_buffer_t
 hb_bool_t
 hb_ot_layout_position_lookup (hb_font_t    *font,
 			      hb_buffer_t  *buffer,
 			      unsigned int  lookup_index,
 			      hb_mask_t     mask);
 
 /* Should be called after all the position_lookup's are done */
 void
-hb_ot_layout_position_finish (hb_face_t *face, hb_buffer_t *buffer);
+hb_ot_layout_position_finish (hb_buffer_t  *buffer);
 
 
 HB_END_DECLS
 
 #endif /* HB_OT_LAYOUT_H */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
@@ -1,51 +1,25 @@
+/* == Start of generated table == */
 /*
- * Copyright © 2011  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
+ * The following table is generated by running:
  *
- * 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.
+ *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
  *
- * 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.
+ * on files with these headers:
  *
- * 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
+ * # ArabicShaping-6.1.0.txt
+ * # Date: 2011-04-15, 23:16:00 GMT [KW]
+ * UnicodeData.txt does not have a header.
  */
 
 #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 
-#include "hb-private.hh"
 
-
-/* == Start of generated table == */
-/*
- * The following table is generated by running:
- *
- *   ./gen-arabic-table.py ArabicShaping.txt
- *
- * on files with these headers:
- *
- * # ArabicShaping-6.1.0.txt
- * # Date: 2011-04-15, 23:16:00 GMT [KW]
- */
 static const uint8_t joining_table[] =
 {
 
   /* Arabic Characters */
 
   JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
   JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
   JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
@@ -747,12 +721,222 @@ static const uint8_t joining_table[] =
   JOINING_TYPE_R, /* 08AB; WAW WITH DOT WITHIN; R; WAW */
   JOINING_TYPE_R, /* 08AC; ROHINGYA YEH; R; ROHINGYA YEH */
 
 };
 
 #define JOINING_TABLE_FIRST	0x0600
 #define JOINING_TABLE_LAST	0x08AC
 
-/* == End of generated table == */
+
+static const uint16_t shaping_table[][4] =
+{
+  {0x0621, 0x0621, 0x0621, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
+  {0x0622, 0x0622, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
+  {0x0623, 0x0623, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
+  {0x0624, 0x0624, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
+  {0x0625, 0x0625, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
+  {0xFE8B, 0xFE8C, 0xFE8A, 0xFE89}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
+  {0x0627, 0x0627, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */
+  {0xFE91, 0xFE92, 0xFE90, 0xFE8F}, /* U+0628 ARABIC LETTER BEH */
+  {0x0629, 0x0629, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */
+  {0xFE97, 0xFE98, 0xFE96, 0xFE95}, /* U+062A ARABIC LETTER TEH */
+  {0xFE9B, 0xFE9C, 0xFE9A, 0xFE99}, /* U+062B ARABIC LETTER THEH */
+  {0xFE9F, 0xFEA0, 0xFE9E, 0xFE9D}, /* U+062C ARABIC LETTER JEEM */
+  {0xFEA3, 0xFEA4, 0xFEA2, 0xFEA1}, /* U+062D ARABIC LETTER HAH */
+  {0xFEA7, 0xFEA8, 0xFEA6, 0xFEA5}, /* U+062E ARABIC LETTER KHAH */
+  {0x062F, 0x062F, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */
+  {0x0630, 0x0630, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */
+  {0x0631, 0x0631, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */
+  {0x0632, 0x0632, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */
+  {0xFEB3, 0xFEB4, 0xFEB2, 0xFEB1}, /* U+0633 ARABIC LETTER SEEN */
+  {0xFEB7, 0xFEB8, 0xFEB6, 0xFEB5}, /* U+0634 ARABIC LETTER SHEEN */
+  {0xFEBB, 0xFEBC, 0xFEBA, 0xFEB9}, /* U+0635 ARABIC LETTER SAD */
+  {0xFEBF, 0xFEC0, 0xFEBE, 0xFEBD}, /* U+0636 ARABIC LETTER DAD */
+  {0xFEC3, 0xFEC4, 0xFEC2, 0xFEC1}, /* U+0637 ARABIC LETTER TAH */
+  {0xFEC7, 0xFEC8, 0xFEC6, 0xFEC5}, /* U+0638 ARABIC LETTER ZAH */
+  {0xFECB, 0xFECC, 0xFECA, 0xFEC9}, /* U+0639 ARABIC LETTER AIN */
+  {0xFECF, 0xFED0, 0xFECE, 0xFECD}, /* U+063A ARABIC LETTER GHAIN */
+  {0x063B, 0x063B, 0x063B, 0x063B}, /* U+063B  */
+  {0x063C, 0x063C, 0x063C, 0x063C}, /* U+063C  */
+  {0x063D, 0x063D, 0x063D, 0x063D}, /* U+063D  */
+  {0x063E, 0x063E, 0x063E, 0x063E}, /* U+063E  */
+  {0x063F, 0x063F, 0x063F, 0x063F}, /* U+063F  */
+  {0x0640, 0x0640, 0x0640, 0x0640}, /* U+0640  */
+  {0xFED3, 0xFED4, 0xFED2, 0xFED1}, /* U+0641 ARABIC LETTER FEH */
+  {0xFED7, 0xFED8, 0xFED6, 0xFED5}, /* U+0642 ARABIC LETTER QAF */
+  {0xFEDB, 0xFEDC, 0xFEDA, 0xFED9}, /* U+0643 ARABIC LETTER KAF */
+  {0xFEDF, 0xFEE0, 0xFEDE, 0xFEDD}, /* U+0644 ARABIC LETTER LAM */
+  {0xFEE3, 0xFEE4, 0xFEE2, 0xFEE1}, /* U+0645 ARABIC LETTER MEEM */
+  {0xFEE7, 0xFEE8, 0xFEE6, 0xFEE5}, /* U+0646 ARABIC LETTER NOON */
+  {0xFEEB, 0xFEEC, 0xFEEA, 0xFEE9}, /* U+0647 ARABIC LETTER HEH */
+  {0x0648, 0x0648, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */
+  {0xFBE8, 0xFBE9, 0xFEF0, 0xFEEF}, /* U+0649 ARABIC LETTER */
+  {0xFEF3, 0xFEF4, 0xFEF2, 0xFEF1}, /* U+064A ARABIC LETTER YEH */
+  {0x064B, 0x064B, 0x064B, 0x064B}, /* U+064B  */
+  {0x064C, 0x064C, 0x064C, 0x064C}, /* U+064C  */
+  {0x064D, 0x064D, 0x064D, 0x064D}, /* U+064D  */
+  {0x064E, 0x064E, 0x064E, 0x064E}, /* U+064E  */
+  {0x064F, 0x064F, 0x064F, 0x064F}, /* U+064F  */
+  {0x0650, 0x0650, 0x0650, 0x0650}, /* U+0650  */
+  {0x0651, 0x0651, 0x0651, 0x0651}, /* U+0651  */
+  {0x0652, 0x0652, 0x0652, 0x0652}, /* U+0652  */
+  {0x0653, 0x0653, 0x0653, 0x0653}, /* U+0653  */
+  {0x0654, 0x0654, 0x0654, 0x0654}, /* U+0654  */
+  {0x0655, 0x0655, 0x0655, 0x0655}, /* U+0655  */
+  {0x0656, 0x0656, 0x0656, 0x0656}, /* U+0656  */
+  {0x0657, 0x0657, 0x0657, 0x0657}, /* U+0657  */
+  {0x0658, 0x0658, 0x0658, 0x0658}, /* U+0658  */
+  {0x0659, 0x0659, 0x0659, 0x0659}, /* U+0659  */
+  {0x065A, 0x065A, 0x065A, 0x065A}, /* U+065A  */
+  {0x065B, 0x065B, 0x065B, 0x065B}, /* U+065B  */
+  {0x065C, 0x065C, 0x065C, 0x065C}, /* U+065C  */
+  {0x065D, 0x065D, 0x065D, 0x065D}, /* U+065D  */
+  {0x065E, 0x065E, 0x065E, 0x065E}, /* U+065E  */
+  {0x065F, 0x065F, 0x065F, 0x065F}, /* U+065F  */
+  {0x0660, 0x0660, 0x0660, 0x0660}, /* U+0660  */
+  {0x0661, 0x0661, 0x0661, 0x0661}, /* U+0661  */
+  {0x0662, 0x0662, 0x0662, 0x0662}, /* U+0662  */
+  {0x0663, 0x0663, 0x0663, 0x0663}, /* U+0663  */
+  {0x0664, 0x0664, 0x0664, 0x0664}, /* U+0664  */
+  {0x0665, 0x0665, 0x0665, 0x0665}, /* U+0665  */
+  {0x0666, 0x0666, 0x0666, 0x0666}, /* U+0666  */
+  {0x0667, 0x0667, 0x0667, 0x0667}, /* U+0667  */
+  {0x0668, 0x0668, 0x0668, 0x0668}, /* U+0668  */
+  {0x0669, 0x0669, 0x0669, 0x0669}, /* U+0669  */
+  {0x066A, 0x066A, 0x066A, 0x066A}, /* U+066A  */
+  {0x066B, 0x066B, 0x066B, 0x066B}, /* U+066B  */
+  {0x066C, 0x066C, 0x066C, 0x066C}, /* U+066C  */
+  {0x066D, 0x066D, 0x066D, 0x066D}, /* U+066D  */
+  {0x066E, 0x066E, 0x066E, 0x066E}, /* U+066E  */
+  {0x066F, 0x066F, 0x066F, 0x066F}, /* U+066F  */
+  {0x0670, 0x0670, 0x0670, 0x0670}, /* U+0670  */
+  {0x0671, 0x0671, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */
+  {0x0672, 0x0672, 0x0672, 0x0672}, /* U+0672  */
+  {0x0673, 0x0673, 0x0673, 0x0673}, /* U+0673  */
+  {0x0674, 0x0674, 0x0674, 0x0674}, /* U+0674  */
+  {0x0675, 0x0675, 0x0675, 0x0675}, /* U+0675  */
+  {0x0676, 0x0676, 0x0676, 0x0676}, /* U+0676  */
+  {0x0677, 0x0677, 0x0677, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
+  {0x0678, 0x0678, 0x0678, 0x0678}, /* U+0678  */
+  {0xFB68, 0xFB69, 0xFB67, 0xFB66}, /* U+0679 ARABIC LETTER TTEH */
+  {0xFB60, 0xFB61, 0xFB5F, 0xFB5E}, /* U+067A ARABIC LETTER TTEHEH */
+  {0xFB54, 0xFB55, 0xFB53, 0xFB52}, /* U+067B ARABIC LETTER BEEH */
+  {0x067C, 0x067C, 0x067C, 0x067C}, /* U+067C  */
+  {0x067D, 0x067D, 0x067D, 0x067D}, /* U+067D  */
+  {0xFB58, 0xFB59, 0xFB57, 0xFB56}, /* U+067E ARABIC LETTER PEH */
+  {0xFB64, 0xFB65, 0xFB63, 0xFB62}, /* U+067F ARABIC LETTER TEHEH */
+  {0xFB5C, 0xFB5D, 0xFB5B, 0xFB5A}, /* U+0680 ARABIC LETTER BEHEH */
+  {0x0681, 0x0681, 0x0681, 0x0681}, /* U+0681  */
+  {0x0682, 0x0682, 0x0682, 0x0682}, /* U+0682  */
+  {0xFB78, 0xFB79, 0xFB77, 0xFB76}, /* U+0683 ARABIC LETTER NYEH */
+  {0xFB74, 0xFB75, 0xFB73, 0xFB72}, /* U+0684 ARABIC LETTER DYEH */
+  {0x0685, 0x0685, 0x0685, 0x0685}, /* U+0685  */
+  {0xFB7C, 0xFB7D, 0xFB7B, 0xFB7A}, /* U+0686 ARABIC LETTER TCHEH */
+  {0xFB80, 0xFB81, 0xFB7F, 0xFB7E}, /* U+0687 ARABIC LETTER TCHEHEH */
+  {0x0688, 0x0688, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */
+  {0x0689, 0x0689, 0x0689, 0x0689}, /* U+0689  */
+  {0x068A, 0x068A, 0x068A, 0x068A}, /* U+068A  */
+  {0x068B, 0x068B, 0x068B, 0x068B}, /* U+068B  */
+  {0x068C, 0x068C, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */
+  {0x068D, 0x068D, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */
+  {0x068E, 0x068E, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */
+  {0x068F, 0x068F, 0x068F, 0x068F}, /* U+068F  */
+  {0x0690, 0x0690, 0x0690, 0x0690}, /* U+0690  */
+  {0x0691, 0x0691, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */
+  {0x0692, 0x0692, 0x0692, 0x0692}, /* U+0692  */
+  {0x0693, 0x0693, 0x0693, 0x0693}, /* U+0693  */
+  {0x0694, 0x0694, 0x0694, 0x0694}, /* U+0694  */
+  {0x0695, 0x0695, 0x0695, 0x0695}, /* U+0695  */
+  {0x0696, 0x0696, 0x0696, 0x0696}, /* U+0696  */
+  {0x0697, 0x0697, 0x0697, 0x0697}, /* U+0697  */
+  {0x0698, 0x0698, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */
+  {0x0699, 0x0699, 0x0699, 0x0699}, /* U+0699  */
+  {0x069A, 0x069A, 0x069A, 0x069A}, /* U+069A  */
+  {0x069B, 0x069B, 0x069B, 0x069B}, /* U+069B  */
+  {0x069C, 0x069C, 0x069C, 0x069C}, /* U+069C  */
+  {0x069D, 0x069D, 0x069D, 0x069D}, /* U+069D  */
+  {0x069E, 0x069E, 0x069E, 0x069E}, /* U+069E  */
+  {0x069F, 0x069F, 0x069F, 0x069F}, /* U+069F  */
+  {0x06A0, 0x06A0, 0x06A0, 0x06A0}, /* U+06A0  */
+  {0x06A1, 0x06A1, 0x06A1, 0x06A1}, /* U+06A1  */
+  {0x06A2, 0x06A2, 0x06A2, 0x06A2}, /* U+06A2  */
+  {0x06A3, 0x06A3, 0x06A3, 0x06A3}, /* U+06A3  */
+  {0xFB6C, 0xFB6D, 0xFB6B, 0xFB6A}, /* U+06A4 ARABIC LETTER VEH */
+  {0x06A5, 0x06A5, 0x06A5, 0x06A5}, /* U+06A5  */
+  {0xFB70, 0xFB71, 0xFB6F, 0xFB6E}, /* U+06A6 ARABIC LETTER PEHEH */
+  {0x06A7, 0x06A7, 0x06A7, 0x06A7}, /* U+06A7  */
+  {0x06A8, 0x06A8, 0x06A8, 0x06A8}, /* U+06A8  */
+  {0xFB90, 0xFB91, 0xFB8F, 0xFB8E}, /* U+06A9 ARABIC LETTER KEHEH */
+  {0x06AA, 0x06AA, 0x06AA, 0x06AA}, /* U+06AA  */
+  {0x06AB, 0x06AB, 0x06AB, 0x06AB}, /* U+06AB  */
+  {0x06AC, 0x06AC, 0x06AC, 0x06AC}, /* U+06AC  */
+  {0xFBD5, 0xFBD6, 0xFBD4, 0xFBD3}, /* U+06AD ARABIC LETTER NG */
+  {0x06AE, 0x06AE, 0x06AE, 0x06AE}, /* U+06AE  */
+  {0xFB94, 0xFB95, 0xFB93, 0xFB92}, /* U+06AF ARABIC LETTER GAF */
+  {0x06B0, 0x06B0, 0x06B0, 0x06B0}, /* U+06B0  */
+  {0xFB9C, 0xFB9D, 0xFB9B, 0xFB9A}, /* U+06B1 ARABIC LETTER NGOEH */
+  {0x06B2, 0x06B2, 0x06B2, 0x06B2}, /* U+06B2  */
+  {0xFB98, 0xFB99, 0xFB97, 0xFB96}, /* U+06B3 ARABIC LETTER GUEH */
+  {0x06B4, 0x06B4, 0x06B4, 0x06B4}, /* U+06B4  */
+  {0x06B5, 0x06B5, 0x06B5, 0x06B5}, /* U+06B5  */
+  {0x06B6, 0x06B6, 0x06B6, 0x06B6}, /* U+06B6  */
+  {0x06B7, 0x06B7, 0x06B7, 0x06B7}, /* U+06B7  */
+  {0x06B8, 0x06B8, 0x06B8, 0x06B8}, /* U+06B8  */
+  {0x06B9, 0x06B9, 0x06B9, 0x06B9}, /* U+06B9  */
+  {0x06BA, 0x06BA, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */
+  {0xFBA2, 0xFBA3, 0xFBA1, 0xFBA0}, /* U+06BB ARABIC LETTER RNOON */
+  {0x06BC, 0x06BC, 0x06BC, 0x06BC}, /* U+06BC  */
+  {0x06BD, 0x06BD, 0x06BD, 0x06BD}, /* U+06BD  */
+  {0xFBAC, 0xFBAD, 0xFBAB, 0xFBAA}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
+  {0x06BF, 0x06BF, 0x06BF, 0x06BF}, /* U+06BF  */
+  {0x06C0, 0x06C0, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
+  {0xFBA8, 0xFBA9, 0xFBA7, 0xFBA6}, /* U+06C1 ARABIC LETTER HEH GOAL */
+  {0x06C2, 0x06C2, 0x06C2, 0x06C2}, /* U+06C2  */
+  {0x06C3, 0x06C3, 0x06C3, 0x06C3}, /* U+06C3  */
+  {0x06C4, 0x06C4, 0x06C4, 0x06C4}, /* U+06C4  */
+  {0x06C5, 0x06C5, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
+  {0x06C6, 0x06C6, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */
+  {0x06C7, 0x06C7, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */
+  {0x06C8, 0x06C8, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */
+  {0x06C9, 0x06C9, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
+  {0x06CA, 0x06CA, 0x06CA, 0x06CA}, /* U+06CA  */
+  {0x06CB, 0x06CB, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */
+  {0xFBFE, 0xFBFF, 0xFBFD, 0xFBFC}, /* U+06CC ARABIC LETTER FARSI YEH */
+  {0x06CD, 0x06CD, 0x06CD, 0x06CD}, /* U+06CD  */
+  {0x06CE, 0x06CE, 0x06CE, 0x06CE}, /* U+06CE  */
+  {0x06CF, 0x06CF, 0x06CF, 0x06CF}, /* U+06CF  */
+  {0xFBE6, 0xFBE7, 0xFBE5, 0xFBE4}, /* U+06D0 ARABIC LETTER E */
+  {0x06D1, 0x06D1, 0x06D1, 0x06D1}, /* U+06D1  */
+  {0x06D2, 0x06D2, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */
+  {0x06D3, 0x06D3, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
+};
+
+#define SHAPING_TABLE_FIRST	0x0621
+#define SHAPING_TABLE_LAST	0x06D3
+
+
+static const struct {
+ uint16_t first;
+ struct {
+   uint16_t second;
+   uint16_t ligature;
+ } ligatures[4];
+} ligature_table[] =
+{
+  { 0xFEDF, {
+    { 0xFE88, 0xFEF9 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+    { 0xFE82, 0xFEF5 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+    { 0xFE8E, 0xFEFB }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+    { 0xFE84, 0xFEF7 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+  }},
+  { 0xFEE0, {
+    { 0xFE88, 0xFEFA }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+    { 0xFE82, 0xFEF6 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+    { 0xFE8E, 0xFEFC }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+    { 0xFE84, 0xFEF8 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+  }},
+};
 
 
 #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */
+
+/* == End of generated table == */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -53,18 +53,16 @@ enum {
 /*
  * Joining types:
  */
 
 #include "hb-ot-shape-complex-arabic-table.hh"
 
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
 {
-  /* TODO Macroize the magic bit operations */
-
   if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) {
     unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
     if (likely (j_type != JOINING_TYPE_X))
       return j_type;
   }
 
   /* Mongolian joining data is not in ArabicJoining.txt yet */
   if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
@@ -77,17 +75,33 @@ static unsigned int get_joining_type (hb
   if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) {
     return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
   }
 
   return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
 	 JOINING_TYPE_T : JOINING_TYPE_U;
 }
 
+static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape)
+{
+  if (likely (hb_in_range<hb_codepoint_t> (u, SHAPING_TABLE_FIRST, SHAPING_TABLE_LAST)) && shape < 4)
+    return shaping_table[u - SHAPING_TABLE_FIRST][shape];
+  return u;
+}
 
+static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
+{
+  if (unlikely (!second)) return 0;
+  for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
+    if (ligature_table[i].first == first)
+      for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
+	if (ligature_table[i].ligatures[j].second == second)
+	  return ligature_table[i].ligatures[j].ligature;
+  return 0;
+}
 
 static const hb_tag_t arabic_syriac_features[] =
 {
   HB_TAG('i','n','i','t'),
   HB_TAG('m','e','d','i'),
   HB_TAG('f','i','n','a'),
   HB_TAG('i','s','o','l'),
   /* Syriac */
@@ -178,24 +192,59 @@ void
 
   map->add_bool_feature (HB_TAG('c','a','l','t'));
   map->add_gsub_pause (NULL, NULL);
 
   /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
   map->add_bool_feature (HB_TAG('c','s','w','h'));
 }
 
-bool
-_hb_ot_shape_complex_prefer_decomposed_arabic (void)
+hb_ot_shape_normalization_mode_t
+_hb_ot_shape_complex_normalization_preference_arabic (void)
+{
+  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+}
+
+
+static void
+arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
 {
-  return FALSE;
+  unsigned int count = buffer->len;
+  hb_codepoint_t glyph;
+
+  /* Shape to presentation forms */
+  for (unsigned int i = 0; i < count; i++) {
+    hb_codepoint_t u = buffer->info[i].codepoint;
+    hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action());
+    if (shaped != u && hb_font_get_glyph (font, shaped, 0, &glyph))
+      buffer->info[i].codepoint = shaped;
+  }
+
+  /* Mandatory ligatures */
+  buffer->clear_output ();
+  for (buffer->idx = 0; buffer->idx + 1 < count;) {
+    uint16_t ligature = get_ligature (buffer->info[buffer->idx].codepoint,
+				      buffer->info[buffer->idx + 1].codepoint);
+    if (likely (!ligature) || !(hb_font_get_glyph (font, ligature, 0, &glyph))) {
+      buffer->next_glyph ();
+      continue;
+    }
+
+    buffer->replace_glyphs (2, 1, &ligature);
+
+    /* Technically speaking we can skip marks and stuff, like the GSUB path does.
+     * But who cares, we're in fallback! */
+  }
+  for (; buffer->idx < count;)
+      buffer->next_glyph ();
+  buffer->swap_buffers ();
 }
 
 void
-_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer)
+_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font)
 {
   unsigned int count = buffer->len;
   unsigned int prev = 0, state = 0;
 
   HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
 
   for (unsigned int i = 0; i < count; i++)
   {
@@ -213,19 +262,34 @@ void
 
     buffer->info[i].arabic_shaping_action() = entry->curr_action;
 
     prev = i;
     state = entry->next_state;
   }
 
   hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
+  hb_mask_t total_masks = 0;
   unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_masks; i++)
+  for (unsigned int i = 0; i < num_masks; i++) {
     mask_array[i] = map->get_1_mask (arabic_syriac_features[i]);
+    total_masks |= mask_array[i];
+  }
 
-  for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()];
+  if (total_masks) {
+    /* Has OpenType tables */
+    for (unsigned int i = 0; i < count; i++)
+      buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()];
+  } else if (buffer->props.script == HB_SCRIPT_ARABIC) {
+    /* Fallback Arabic shaping to Presentation Forms */
+    /* Pitfalls:
+     * - This path fires if user force-set init/medi/fina/isol off,
+     * - If font does not declare script 'arab', well, what to do?
+     *   Most probably it's safe to assume that init/medi/fina/isol
+     *   still mean Arabic shaping, although they do not have to.
+     */
+    arabic_fallback_shape (font, buffer);
+  }
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
@@ -1,10 +1,10 @@
 
-#line 1 "hb-ot-shape-complex-indic-machine.rl"
+#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
 /*
  * 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
@@ -29,77 +29,77 @@
 #ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
 #define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
 
 #include "hb-private.hh"
 
 HB_BEGIN_DECLS
 
 
-#line 38 "hb-ot-shape-complex-indic-machine.hh"
+#line 38 "hb-ot-shape-complex-indic-machine.hh.tmp"
 static const unsigned char _indic_syllable_machine_trans_keys[] = {
-	0u, 0u, 5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 5u, 5u, 1u, 2u, 
+	0u, 0u, 1u, 2u, 1u, 2u, 5u, 5u, 5u, 5u, 1u, 5u, 5u, 5u, 1u, 2u, 
 	0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 
 	0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 
 	0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 
 	0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 
 	0u, 12u, 0
 };
 
 static const char _indic_syllable_machine_key_spans[] = {
-	0, 1, 2, 2, 1, 5, 1, 2, 
+	0, 2, 2, 1, 1, 5, 1, 2, 
 	13, 13, 13, 13, 13, 13, 13, 13, 
 	13, 13, 13, 13, 13, 13, 13, 13, 
 	13, 13, 13, 13, 13, 13, 13, 13, 
 	13, 13, 13, 13, 13, 13, 13, 13, 
 	13
 };
 
 static const short _indic_syllable_machine_index_offsets[] = {
-	0, 0, 2, 5, 8, 10, 16, 18, 
+	0, 0, 3, 6, 8, 10, 16, 18, 
 	21, 35, 49, 63, 77, 91, 105, 119, 
 	133, 147, 161, 175, 189, 203, 217, 231, 
 	245, 259, 273, 287, 301, 315, 329, 343, 
 	357, 371, 385, 399, 413, 427, 441, 455, 
 	469
 };
 
 static const char _indic_syllable_machine_indicies[] = {
-	0, 1, 2, 2, 1, 3, 3, 
-	1, 4, 1, 2, 2, 1, 1, 0, 
+	0, 0, 1, 2, 2, 1, 3, 
+	1, 4, 1, 0, 0, 1, 1, 4, 
 	1, 5, 1, 6, 6, 1, 7, 6, 
 	8, 9, 1, 1, 1, 1, 1, 1, 
 	1, 1, 10, 1, 11, 12, 13, 14, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	15, 1, 16, 17, 18, 19, 20, 21, 
 	22, 22, 23, 24, 25, 26, 27, 1, 
 	16, 17, 18, 19, 20, 28, 22, 22, 
 	23, 24, 25, 26, 27, 1, 29, 30, 
-	31, 32, 33, 1, 34, 35, 36, 37, 
+	31, 32, 33, 4, 34, 35, 36, 37, 
 	38, 1, 39, 1, 29, 30, 31, 32, 
-	1, 1, 34, 35, 36, 37, 38, 1, 
+	1, 4, 34, 35, 36, 37, 38, 1, 
 	39, 1, 29, 30, 31, 32, 1, 1, 
 	1, 1, 36, 37, 38, 1, 39, 1, 
-	29, 30, 31, 32, 40, 2, 1, 1, 
+	29, 30, 31, 32, 40, 0, 1, 1, 
 	36, 37, 38, 1, 39, 1, 29, 30, 
-	31, 32, 1, 2, 1, 1, 36, 37, 
+	31, 32, 1, 0, 1, 1, 36, 37, 
 	38, 1, 39, 1, 29, 30, 31, 32, 
 	1, 1, 1, 1, 1, 1, 38, 1, 
 	39, 1, 29, 30, 31, 32, 1, 1, 
 	1, 1, 1, 1, 41, 1, 39, 1, 
 	29, 30, 31, 32, 1, 1, 1, 1, 
 	1, 1, 1, 1, 39, 1, 42, 43, 
-	44, 45, 46, 4, 47, 47, 48, 49, 
+	44, 45, 46, 3, 47, 47, 48, 49, 
 	50, 1, 51, 1, 42, 43, 44, 45, 
-	1, 4, 47, 47, 48, 49, 50, 1, 
+	1, 3, 47, 47, 48, 49, 50, 1, 
 	51, 1, 42, 43, 44, 45, 1, 1, 
 	1, 1, 48, 49, 50, 1, 51, 1, 
-	42, 43, 44, 45, 52, 3, 1, 1, 
+	42, 43, 44, 45, 52, 2, 1, 1, 
 	48, 49, 50, 1, 51, 1, 42, 43, 
-	44, 45, 1, 3, 1, 1, 48, 49, 
+	44, 45, 1, 2, 1, 1, 48, 49, 
 	50, 1, 51, 1, 42, 43, 44, 45, 
 	1, 1, 1, 1, 1, 1, 50, 1, 
 	51, 1, 42, 43, 44, 45, 1, 1, 
 	1, 1, 1, 1, 53, 1, 51, 1, 
 	42, 43, 44, 45, 1, 1, 1, 1, 
 	1, 1, 1, 1, 51, 1, 16, 17, 
 	18, 19, 1, 21, 22, 22, 23, 24, 
 	25, 26, 27, 1, 16, 6, 6, 19, 
@@ -122,22 +122,22 @@ static const char _indic_syllable_machin
 	59, 59, 1, 24, 25, 1, 27, 1, 
 	16, 17, 18, 19, 1, 1, 1, 1, 
 	1, 24, 25, 1, 27, 1, 16, 6, 
 	6, 9, 1, 1, 54, 54, 1, 24, 
 	25, 1, 10, 1, 0
 };
 
 static const char _indic_syllable_machine_trans_targs[] = {
-	2, 0, 14, 22, 3, 7, 10, 9, 
+	14, 0, 22, 2, 1, 7, 10, 9, 
 	11, 12, 20, 9, 10, 11, 12, 20, 
 	9, 10, 11, 12, 28, 29, 6, 34, 
 	31, 32, 37, 20, 40, 9, 10, 11, 
-	12, 13, 1, 5, 15, 17, 18, 20, 
-	16, 19, 9, 10, 11, 12, 21, 4, 
+	12, 13, 4, 5, 15, 17, 18, 20, 
+	16, 19, 9, 10, 11, 12, 21, 3, 
 	23, 25, 26, 20, 24, 27, 30, 33, 
 	35, 36, 38, 39
 };
 
 static const char _indic_syllable_machine_trans_actions[] = {
 	0, 0, 0, 0, 0, 0, 0, 0, 
 	0, 0, 0, 1, 1, 1, 1, 1, 
 	2, 2, 2, 2, 0, 0, 0, 0, 
@@ -159,56 +159,44 @@ static const char _indic_syllable_machin
 
 static const int indic_syllable_machine_start = 8;
 static const int indic_syllable_machine_first_final = 8;
 static const int indic_syllable_machine_error = 0;
 
 static const int indic_syllable_machine_en_main = 8;
 
 
-#line 38 "hb-ot-shape-complex-indic-machine.rl"
-
-
-
-#line 83 "hb-ot-shape-complex-indic-machine.rl"
+#line 38 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
 
-static void
-set_cluster (hb_buffer_t *buffer,
-	     unsigned int start, unsigned int end)
-{
-  unsigned int cluster = buffer->info[start].cluster;
+#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
-  for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, buffer->info[i].cluster);
-  for (unsigned int i = start; i < end; i++)
-    buffer->info[i].cluster = cluster;
-}
+
 
 static void
 find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
 {
   unsigned int p, pe, eof;
   int cs;
   
-#line 194 "hb-ot-shape-complex-indic-machine.hh"
+#line 182 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	cs = indic_syllable_machine_start;
 	}
 
-#line 106 "hb-ot-shape-complex-indic-machine.rl"
+#line 94 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 
   p = 0;
   pe = eof = buffer->len;
 
   unsigned int last = 0;
   
-#line 207 "hb-ot-shape-complex-indic-machine.hh"
+#line 195 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	{
 	int _slen;
 	int _trans;
 	const unsigned char *_keys;
 	const char *_inds;
 	if ( p == pe )
 		goto _test_eof;
 	if ( cs == 0 )
@@ -224,81 +212,81 @@ find_syllables (const hb_ot_map_t *map, 
 
 	cs = _indic_syllable_machine_trans_targs[_trans];
 
 	if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
 		goto _again;
 
 	switch ( _indic_syllable_machine_trans_actions[_trans] ) {
 	case 2:
-#line 62 "hb-ot-shape-complex-indic-machine.rl"
+#line 62 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_consonant_syllable (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 3:
-#line 63 "hb-ot-shape-complex-indic-machine.rl"
+#line 63 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_vowel_syllable (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 4:
-#line 64 "hb-ot-shape-complex-indic-machine.rl"
+#line 64 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_standalone_cluster (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 1:
-#line 65 "hb-ot-shape-complex-indic-machine.rl"
+#line 65 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_non_indic (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
-#line 256 "hb-ot-shape-complex-indic-machine.hh"
+#line 244 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 
 _again:
 	if ( cs == 0 )
 		goto _out;
 	if ( ++p != pe )
 		goto _resume;
 	_test_eof: {}
 	if ( p == eof )
 	{
 	switch ( _indic_syllable_machine_eof_actions[cs] ) {
 	case 2:
-#line 62 "hb-ot-shape-complex-indic-machine.rl"
+#line 62 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_consonant_syllable (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 3:
-#line 63 "hb-ot-shape-complex-indic-machine.rl"
+#line 63 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_vowel_syllable (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 4:
-#line 64 "hb-ot-shape-complex-indic-machine.rl"
+#line 64 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_standalone_cluster (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
 	case 1:
-#line 65 "hb-ot-shape-complex-indic-machine.rl"
+#line 65 "../../src/hb-ot-shape-complex-indic-machine.rl"
 	{ found_non_indic (map, buffer, mask_array, last, p); }
-#line 67 "hb-ot-shape-complex-indic-machine.rl"
-	{ set_cluster (buffer, last, p); last = p; }
+#line 67 "../../src/hb-ot-shape-complex-indic-machine.rl"
+	{ buffer->merge_clusters (last, p); last = p; }
 	break;
-#line 292 "hb-ot-shape-complex-indic-machine.hh"
+#line 280 "hb-ot-shape-complex-indic-machine.hh.tmp"
 	}
 	}
 
 	_out: {}
 	}
 
-#line 114 "hb-ot-shape-complex-indic-machine.rl"
+#line 102 "../../src/hb-ot-shape-complex-indic-machine.rl"
 
 }
 
 HB_END_DECLS
 
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl
@@ -59,48 +59,36 @@ z = ZWJ|ZWNJ;
 matra_group = M N? H?;
 syllable_tail = SM? (VD VD?)?;
 
 action found_consonant_syllable { found_consonant_syllable (map, buffer, mask_array, last, p); }
 action found_vowel_syllable { found_vowel_syllable (map, buffer, mask_array, last, p); }
 action found_standalone_cluster { found_standalone_cluster (map, buffer, mask_array, last, p); }
 action found_non_indic { found_non_indic (map, buffer, mask_array, last, p); }
 
-action next_syllable { set_cluster (buffer, last, p); last = p; }
+action next_syllable { buffer->merge_clusters (last, p); last = p; }
 
-consonant_syllable =	(c.N? (z.H|H.z?))* c.N? A? (H.z? | matra_group*)? syllable_tail %(found_consonant_syllable);
-vowel_syllable =	(Ra H)? V N? (z.H.c | ZWJ.c)? matra_group* syllable_tail %(found_vowel_syllable);
+consonant_syllable =	(c.N? (H.z?|z.H))* c.N? A? (H.z? | matra_group*)? syllable_tail %(found_consonant_syllable);
+vowel_syllable =	(Ra H)? V N? (z?.H.c | ZWJ.c)? matra_group* syllable_tail %(found_vowel_syllable);
 standalone_cluster =	(Ra H)? NBSP N? (z? H c)? matra_group* syllable_tail %(found_standalone_cluster);
 non_indic = X %(found_non_indic);
 
 syllable =
 	  consonant_syllable
 	| vowel_syllable
 	| standalone_cluster
 	| non_indic
 	;
 
 main := (syllable %(next_syllable))**;
 
 }%%
 
 
 static void
-set_cluster (hb_buffer_t *buffer,
-	     unsigned int start, unsigned int end)
-{
-  unsigned int cluster = buffer->info[start].cluster;
-
-  for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, buffer->info[i].cluster);
-  for (unsigned int i = start; i < end; i++)
-    buffer->info[i].cluster = cluster;
-}
-
-static void
 find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
 {
   unsigned int p, pe, eof;
   int cs;
   %%{
     write init;
     getkey buffer->info[p].indic_category();
   }%%
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.hh
@@ -1,99 +1,70 @@
-/*
- * 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_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-
-#include "hb-private.hh"
-
-
 /* == Start of generated table == */
 /*
  * The following table is generated by running:
  *
  *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-6.0.0.txt
- * # Date: 2010-05-25, 11:45:00 PDT [KW]
- * # IndicMatraCategory-6.0.0.txt
- * # Date: 2010-07-14, 15:03:00 PDT [KW]
- * # Blocks-6.0.0.txt
- * # Date: 2010-06-04, 11:12:00 PDT [KW]
+ * # IndicSyllabicCategory-6.1.0.txt
+ * # Date: 2011-08-31, 23:54:00 GMT [KW]
+ * # IndicMatraCategory-6.1.0.txt
+ * # Date: 2011-08-31, 23:50:00 GMT [KW]
+ * # Blocks-6.1.0.txt
+ * # Date: 2011-06-14, 18:26:00 GMT [KW, LI]
  */
 
+#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
+#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
 
-#define ISC_A	INDIC_SYLLABIC_CATEGORY_AVAGRAHA		/*   9 chars; Avagraha */
-#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  31 chars; Bindu */
-#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 116 chars; Consonant */
+
+#define ISC_A	INDIC_SYLLABIC_CATEGORY_AVAGRAHA		/*  11 chars; Avagraha */
+#define ISC_Bi	INDIC_SYLLABIC_CATEGORY_BINDU			/*  34 chars; Bindu */
+#define ISC_C	INDIC_SYLLABIC_CATEGORY_CONSONANT		/* 123 chars; Consonant */
 #define ISC_CD	INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD		/*   2 chars; Consonant_Dead */
-#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  16 chars; Consonant_Final */
+#define ISC_CF	INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL		/*  17 chars; Consonant_Final */
 #define ISC_CHL	INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER	/*   1 chars; Consonant_Head_Letter */
 #define ISC_CM	INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL	/*  12 chars; Consonant_Medial */
 #define ISC_CP	INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER	/*   4 chars; Consonant_Placeholder */
 #define ISC_CR	INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA		/*   5 chars; Consonant_Repha */
-#define ISC_CS	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED	/*   9 chars; Consonant_Subjoined */
+#define ISC_CS	INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED	/*  10 chars; Consonant_Subjoined */
 #define ISC_ML	INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER	/*   1 chars; Modifying_Letter */
-#define ISC_N	INDIC_SYLLABIC_CATEGORY_NUKTA			/*  11 chars; Nukta */
+#define ISC_N	INDIC_SYLLABIC_CATEGORY_NUKTA			/*  12 chars; Nukta */
 #define ISC_x	INDIC_SYLLABIC_CATEGORY_OTHER			/*   1 chars; Other */
 #define ISC_RS	INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER	/*   1 chars; Register_Shifter */
 #define ISC_TL	INDIC_SYLLABIC_CATEGORY_TONE_LETTER		/*   3 chars; Tone_Letter */
 #define ISC_TM	INDIC_SYLLABIC_CATEGORY_TONE_MARK		/*  16 chars; Tone_Mark */
-#define ISC_V	INDIC_SYLLABIC_CATEGORY_VIRAMA			/*  29 chars; Virama */
-#define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  19 chars; Visarga */
+#define ISC_V	INDIC_SYLLABIC_CATEGORY_VIRAMA			/*  34 chars; Virama */
+#define ISC_Vs	INDIC_SYLLABIC_CATEGORY_VISARGA			/*  25 chars; Visarga */
 #define ISC_Vo	INDIC_SYLLABIC_CATEGORY_VOWEL			/*   5 chars; Vowel */
-#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 161 chars; Vowel_Dependent */
-#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/*  53 chars; Vowel_Independent */
+#define ISC_M	INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT		/* 165 chars; Vowel_Dependent */
+#define ISC_VI	INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	/*  59 chars; Vowel_Independent */
 
-#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/*  60 chars; Bottom */
+#define IMC_B	INDIC_MATRA_CATEGORY_BOTTOM			/*  65 chars; Bottom */
 #define IMC_BR	INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT		/*   2 chars; Bottom_And_Right */
-#define IMC_I	INDIC_MATRA_CATEGORY_INVISIBLE			/*   4 chars; Invisible */
-#define IMC_L	INDIC_MATRA_CATEGORY_LEFT			/*  25 chars; Left */
+#define IMC_I	INDIC_MATRA_CATEGORY_INVISIBLE			/*   6 chars; Invisible */
+#define IMC_L	INDIC_MATRA_CATEGORY_LEFT			/*  30 chars; Left */
 #define IMC_LR	INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT		/*   8 chars; Left_And_Right */
 #define IMC_x	INDIC_MATRA_CATEGORY_NOT_APPLICABLE		/*   1 chars; Not_Applicable */
 #define IMC_O	INDIC_MATRA_CATEGORY_OVERSTRUCK			/*   2 chars; Overstruck */
-#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/*  70 chars; Right */
-#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/*  74 chars; Top */
-#define IMC_TB	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM		/*   5 chars; Top_And_Bottom */
+#define IMC_R	INDIC_MATRA_CATEGORY_RIGHT			/*  75 chars; Right */
+#define IMC_T	INDIC_MATRA_CATEGORY_TOP			/*  83 chars; Top */
+#define IMC_TB	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM		/*   6 chars; Top_And_Bottom */
 #define IMC_TBR	INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT	/*   1 chars; Top_And_Bottom_And_Right */
 #define IMC_TL	INDIC_MATRA_CATEGORY_TOP_AND_LEFT		/*   4 chars; Top_And_Left */
 #define IMC_TLR	INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT	/*   2 chars; Top_And_Left_And_Right */
-#define IMC_TR	INDIC_MATRA_CATEGORY_TOP_AND_RIGHT		/*   7 chars; Top_And_Right */
+#define IMC_TR	INDIC_MATRA_CATEGORY_TOP_AND_RIGHT		/*   8 chars; Top_And_Right */
 #define IMC_VOL	INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT		/*   5 chars; Visual_Order_Left */
 
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
 
 
-static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = {
+static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
 
 
 #define indic_offset_0x0900 0
 
 
   /* Devanagari  (0900..097F) */
 
   /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -529,19 +500,19 @@ static const INDIC_TABLE_ELEMENT_TYPE in
 
   /* Sundanese  (1B80..1BBF) */
 
   /* 1B80 */ _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B88 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B90 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BA0 */  _(C,x), _(CS,x), _(CS,x), _(CS,x),  _(M,T),  _(M,B),  _(M,L),  _(M,R),
-  /* 1BA8 */  _(M,T),  _(M,T),  _(V,R),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),
+  /* 1BA8 */  _(M,T),  _(M,T),  _(V,R),  _(V,x), _(CS,x), _(CS,x),  _(C,x),  _(C,x),
   /* 1BB0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1BB8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1BB8 */  _(x,x),  _(x,x),  _(A,x),  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x),
 
   /* Batak  (1BC0..1BFF) */
 
   /* 1BC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BE0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),  _(N,x),  _(M,x),
@@ -557,17 +528,29 @@ static const INDIC_TABLE_ELEMENT_TYPE in
   /* 1C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CS,x), _(CS,x),  _(M,R),  _(M,L),
   /* 1C28 */  _(M,L), _(M,TL),  _(M,R),  _(M,R),  _(M,B), _(CF,x), _(CF,x), _(CF,x),
   /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,x), _(Bi,x),  _(x,x),  _(N,x),
   /* 1C38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1C40 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1C48 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
 
-#define indic_offset_0xa800 2976
+#define indic_offset_0x1cd0 2976
+
+
+  /* Vedic Extensions  (1CD0..1CFF) */
+
+  /* 1CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0xa800 3024
 
 
   /* Syloti Nagri  (A800..A82F) */
 
   /* A800 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(V,T),  _(C,x),
   /* A808 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A810 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A818 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -691,31 +674,38 @@ static const INDIC_TABLE_ELEMENT_TYPE in
   /* AAA8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AAB0 */  _(M,T),  _(M,R),  _(M,T),  _(M,T),  _(M,B),_(M,VOL),_(M,VOL),  _(M,T),
   /* AAB8 */  _(M,T),_(M,VOL),  _(M,R),_(M,VOL),_(M,VOL),  _(M,R),  _(M,T), _(TM,x),
   /* AAC0 */ _(TL,x), _(TM,x), _(TL,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAC8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0xabc0 3712
+  /* Meetei Mayek Extensions  (AAE0..AAFF) */
+
+  /* AAE0 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* AAE8 */  _(C,x),  _(C,x),  _(C,x),  _(M,L),  _(M,B),  _(M,T),  _(M,L),  _(M,R),
+  /* AAF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Vs,x),  _(V,I),  _(x,x),
+  /* AAF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0xabc0 3792
 
 
   /* Meetei Mayek  (ABC0..ABFF) */
 
   /* ABC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* ABC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* ABD0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* ABC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),
+  /* ABD0 */  _(C,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* ABD8 */  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* ABE0 */ _(CF,x), _(CF,x), _(CF,x),  _(M,R),  _(M,R),  _(M,T),  _(M,R),  _(M,R),
   /* ABE8 */  _(M,B),  _(M,R),  _(M,R),  _(x,x), _(TM,x),  _(V,B),  _(x,x),  _(x,x),
   /* ABF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* ABF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x10a00 3776
+#define indic_offset_0x10a00 3856
 
 
   /* Kharoshthi  (10A00..10A5F) */
 
   /* 10A00 */  _(C,x),  _(M,O),  _(M,B),  _(M,B),  _(x,x),  _(M,T),  _(M,O),  _(x,x),
   /* 10A08 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,B),  _(x,x), _(Bi,x), _(Vs,x),
   /* 10A10 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A18 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -723,17 +713,17 @@ static const INDIC_TABLE_ELEMENT_TYPE in
   /* 10A28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 10A38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(V,I),
   /* 10A40 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 10A48 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 10A50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 10A58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11000 3872
+#define indic_offset_0x11000 3952
 
 
   /* Brahmi  (11000..1107F) */
 
   /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11010 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11018 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -758,31 +748,85 @@ static const INDIC_TABLE_ELEMENT_TYPE in
   /* 11098 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110B0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,R),
   /* 110B8 */  _(M,R),  _(V,B),  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 110C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 110C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_total 4080
+#define indic_offset_0x11100 4160
+
+
+  /* Chakma  (11100..1114F) */
+
+  /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
+  /* 11108 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11110 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11118 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11120 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),
+  /* 11128 */  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,L),  _(M,T), _(M,TB), _(M,TB),
+  /* 11130 */  _(M,T),  _(M,B),  _(M,B),  _(V,I),  _(V,T),  _(x,x),  _(x,x),  _(x,x),
+  /* 11138 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11140 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11148 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x11180 4240
+
+
+  /* Sharada  (11180..111DF) */
 
-};
+  /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11190 */ _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11198 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 111A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 111A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 111B0 */  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),
+  /* 111B8 */  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T), _(M,TR),
+  /* 111C0 */  _(V,R),  _(A,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x11680 4336
+
+
+  /* Takri  (11680..116CF) */
+
+  /* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11688 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11690 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11698 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 116A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 116A8 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x), _(Vs,x),  _(M,T),  _(M,L),  _(M,R),
+  /* 116B0 */  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(N,x),
+  /* 116B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 116C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_total 4416
+
+}; /* Table occupancy: 60% */
 
 static INDIC_TABLE_ELEMENT_TYPE
 get_indic_categories (hb_codepoint_t u)
 {
   if (0x0900 <= u && u <= 0x10A0) return indic_table[u - 0x0900 + indic_offset_0x0900];
   if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700];
   if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900];
   if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00];
-  if (0xA800 <= u && u <= 0xAAE0) return indic_table[u - 0xA800 + indic_offset_0xa800];
+  if (0x1CD0 <= u && u <= 0x1D00) return indic_table[u - 0x1CD0 + indic_offset_0x1cd0];
+  if (0xA800 <= u && u <= 0xAB00) return indic_table[u - 0xA800 + indic_offset_0xa800];
   if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0];
   if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00];
   if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000];
+  if (0x11100 <= u && u <= 0x11150) return indic_table[u - 0x11100 + indic_offset_0x11100];
+  if (0x11180 <= u && u <= 0x111E0) return indic_table[u - 0x11180 + indic_offset_0x11180];
+  if (0x11680 <= u && u <= 0x116D0) return indic_table[u - 0x11680 + indic_offset_0x11680];
   if (unlikely (u == 0x00A0)) return _(CP,x);
   if (unlikely (u == 0x25CC)) return _(CP,x);
   return _(x,x);
 }
 
 #undef _
 
 #undef ISC_A
@@ -818,13 +862,11 @@ get_indic_categories (hb_codepoint_t u)
 #undef IMC_T
 #undef IMC_TB
 #undef IMC_TBR
 #undef IMC_TL
 #undef IMC_TLR
 #undef IMC_TR
 #undef IMC_VOL
 
+#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */
 
 /* == End of generated table == */
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
@@ -52,21 +52,21 @@ enum indic_category_t {
   OT_SM,
   OT_VD,
   OT_A,
   OT_NBSP
 };
 
 /* Visual positions in a syllable from left to right. */
 enum indic_position_t {
-  POS_PRE,
-  POS_BASE,
-  POS_ABOVE,
-  POS_BELOW,
-  POS_POST
+  POS_PRE = 1,
+  POS_BASE = 3,
+  POS_ABOVE = 5,
+  POS_BELOW = 7,
+  POS_POST = 9
 };
 
 /* Categories used in IndicSyllabicCategory.txt from UCD */
 /* The assignments are guesswork */
 enum indic_syllabic_category_t {
   INDIC_SYLLABIC_CATEGORY_OTHER			= OT_X,
 
   INDIC_SYLLABIC_CATEGORY_AVAGRAHA		= OT_X,
@@ -90,17 +90,17 @@ enum indic_syllabic_category_t {
   INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT	= OT_M,
   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT	= OT_V
 };
 
 /* Categories used in IndicSMatraCategory.txt from UCD */
 enum indic_matra_category_t {
   INDIC_MATRA_CATEGORY_NOT_APPLICABLE		= POS_BASE,
 
-  INDIC_MATRA_CATEGORY_LEFT			= POS_PRE,
+  INDIC_MATRA_CATEGORY_LEFT			= POS_PRE - 1, /* Move *before* existing "pre" chars */
   INDIC_MATRA_CATEGORY_TOP			= POS_ABOVE,
   INDIC_MATRA_CATEGORY_BOTTOM			= POS_BELOW,
   INDIC_MATRA_CATEGORY_RIGHT			= POS_POST,
 
   /* We don't really care much about these since we decompose them
    * in the generic pre-shaping layer.  They will only be used if
    * the font does not cover the decomposition.  In which case, we
    * define these as aliases to the place we want the split-matra
@@ -364,26 +364,26 @@ void
 
   map->add_gsub_pause (final_reordering, NULL);
 
   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++)
     map->add_bool_feature (indic_other_features[i], true);
 }
 
 
-bool
-_hb_ot_shape_complex_prefer_decomposed_indic (void)
+hb_ot_shape_normalization_mode_t
+_hb_ot_shape_complex_normalization_preference_indic (void)
 {
   /* We want split matras decomposed by the common shaping logic. */
-  return TRUE;
+  return HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
 }
 
 
 void
-_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer)
+_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
 
   /* We cannot setup masks here.  We save information about characters
    * and setup masks later on in a pause-callback. */
 
   unsigned int count = buffer->len;
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-misc.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-misc.cc
@@ -22,34 +22,162 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-shape-complex-private.hh"
 
 
-/* TODO Add kana, hangul, and other small sahpers here */
+/* TODO Add kana, and other small shapers here */
 
 /* When adding trivial shapers, eg. kana, hangul, etc, we can either
  * add a full shaper enum value for them, or switch on the script in
  * the default complex shaper.  The former is faster, so I think that's
  * what we would do, and hence the default complex shaper shall remain
  * empty.
  */
 
 void
 _hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map, const hb_segment_properties_t  *props)
 {
 }
 
-bool
-_hb_ot_shape_complex_prefer_decomposed_default (void)
+hb_ot_shape_normalization_mode_t
+_hb_ot_shape_complex_normalization_preference_default (void)
 {
-  return FALSE;
+  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
 }
 
 void
-_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map, hb_buffer_t *buffer)
+_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font)
+{
+}
+
+
+
+/* Hangul shaper */
+
+static const hb_tag_t hangul_features[] =
+{
+  HB_TAG('l','j','m','o'),
+  HB_TAG('v','j','m','o'),
+  HB_TAG('t','j','m','o'),
+};
+
+void
+_hb_ot_shape_complex_collect_features_hangul (hb_ot_map_builder_t *map, const hb_segment_properties_t  *props)
+{
+  for (unsigned int i = 0; i < ARRAY_LENGTH (hangul_features); i++)
+    map->add_bool_feature (hangul_features[i]);
+}
+
+hb_ot_shape_normalization_mode_t
+_hb_ot_shape_complex_normalization_preference_hangul (void)
+{
+  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
+}
+
+void
+_hb_ot_shape_complex_setup_masks_hangul (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font)
 {
 }
 
 
+
+/* Thai / Lao shaper */
+
+void
+_hb_ot_shape_complex_collect_features_thai (hb_ot_map_builder_t *map, const hb_segment_properties_t  *props)
+{
+}
+
+hb_ot_shape_normalization_mode_t
+_hb_ot_shape_complex_normalization_preference_thai (void)
+{
+  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
+}
+
+void
+_hb_ot_shape_complex_setup_masks_thai (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font)
+{
+  /* The following is NOT specified in the MS OT Thai spec, however, it seems
+   * to be what Uniscribe and other engines implement.  According to Eric Muller:
+   *
+   * When you have a sara am, decompose it in nikhahit + sara a, *and* mode the
+   * nihka hit backwards over any *tone* mark (0E48-0E4B).
+   *
+   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
+   *
+   * This reordering is legit only when the nikhahit comes from a sara am, not
+   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
+   * not what a u↪ser wanted, but the rendering is nevertheless nikhahit above
+   * chattawa.
+   *
+   * Same for Lao.
+   */
+
+  /*
+   * Here are the characters of significance:
+   *
+   *			Thai	Lao
+   * SARA AM:		U+0E33	U+0EB3
+   * SARA AA:		U+0E32	U+0EB2
+   * Nikhahit:		U+0E4D	U+0ECD
+   *
+   * Tone marks:
+   * Thai:	<0E48..0E4B> CCC=107
+   * Lao:	<0EC8..0ECB> CCC=122
+   *
+   * Note how the Lao versions are the same as Thai + 0x80.
+   */
+
+  /* We only get one script at a time, so a script-agnostic implementation
+   * is adequate here. */
+#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
+#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
+#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
+#define IS_TONE_MARK(x) (((x) & ~0x0083) == 0x0E48)
+
+  buffer->clear_output ();
+  unsigned int count = buffer->len;
+  for (buffer->idx = 0; buffer->idx < count;)
+  {
+    hb_codepoint_t u = buffer->info[buffer->idx].codepoint;
+    if (likely (!IS_SARA_AM (u))) {
+      buffer->next_glyph ();
+      continue;
+    }
+
+    /* Is SARA AM. Decompose and reorder. */
+    uint16_t decomposed[2] = {uint16_t (NIKHAHIT_FROM_SARA_AM (u)),
+			      uint16_t (SARA_AA_FROM_SARA_AM (u))};
+    buffer->replace_glyphs (1, 2, decomposed);
+    if (unlikely (buffer->in_error))
+      return;
+
+    /* Ok, let's see... */
+    unsigned int end = buffer->out_len;
+    unsigned int start = end - 2;
+    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+      start--;
+
+    /* Move Nikhahit (end-2) to the beginning */
+    hb_glyph_info_t t = buffer->out_info[end - 2];
+    memmove (buffer->out_info + start + 1,
+	     buffer->out_info + start,
+	     sizeof (buffer->out_info[0]) * (end - start - 2));
+    buffer->out_info[start] = t;
+
+    /* Make cluster */
+    for (; start > 0 && buffer->out_info[start - 1].cluster == buffer->out_info[start].cluster; start--)
+      ;
+    for (; buffer->idx < count;)
+      if (buffer->info[buffer->idx].cluster == buffer->out_info[buffer->out_len - 1].cluster)
+        buffer->next_glyph ();
+      else
+        break;
+    end = buffer->out_len;
+
+    buffer->merge_out_clusters (start, end);
+  }
+  buffer->swap_buffers ();
+}
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -25,16 +25,17 @@
  */
 
 #ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH
 #define HB_OT_SHAPE_COMPLEX_PRIVATE_HH
 
 #include "hb-private.hh"
 
 #include "hb-ot-map-private.hh"
+#include "hb-ot-shape-normalize-private.hh"
 
 
 
 /* buffer var allocations, used during the entire shaping process */
 #define general_category() var1.u8[0] /* unicode general_category (hb_unicode_general_category_t) */
 #define combining_class() var1.u8[1] /* unicode combining_class (uint8_t) */
 
 /* buffer var allocations, used by complex shapers */
@@ -44,17 +45,19 @@
 #define complex_var_temporary_u8_0()	var2.u8[2]
 #define complex_var_temporary_u8_1()	var2.u8[3]
 #define complex_var_temporary_u16()	var2.u16[1]
 
 
 #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
   HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
   HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
   HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
   /* ^--- Add new shapers here */
 
 enum hb_ot_complex_shaper_t {
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) hb_ot_complex_shaper_##name,
   HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
   /* Just here to avoid enum trailing comma: */
   hb_ot_complex_shaper_generic = hb_ot_complex_shaper_default
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
@@ -63,83 +66,157 @@ enum hb_ot_complex_shaper_t {
 static inline hb_ot_complex_shaper_t
 hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
 {
   switch ((int) props->script)
   {
     default:
       return hb_ot_complex_shaper_default;
 
+
+    /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
-    case HB_SCRIPT_MANDAIC:
     case HB_SCRIPT_MONGOLIAN:
+    case HB_SCRIPT_SYRIAC:
+
+    /* Unicode-5.0 additions */
     case HB_SCRIPT_NKO:
-    case HB_SCRIPT_SYRIAC:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_MANDAIC:
+
       return hb_ot_complex_shaper_arabic;
 
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HANGUL:
+
+      return hb_ot_complex_shaper_hangul;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_THAI:
+    case HB_SCRIPT_LAO:
+
+      return hb_ot_complex_shaper_thai;
+
+
+
+    /* ^--- Add new shapers here */
+
+
 #if 0
     /* Note:
      *
      * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according
-     * to Martin Hosken do not require complex shaping.
+     * to Martin Hosken and Jonathan Kew do not require complex shaping.
+     *
+     * TODO We should automate figuring out which scripts do not need complex shaping
      *
      * TODO We currently keep data for these scripts in our indic table.  Need to fix the
      * generator to not do that.
      */
 
+
     /* Simple? */
-    case HB_SCRIPT_BATAK:
-    case HB_SCRIPT_BRAHMI:
+
+    /* Unicode-3.2 additions */
+    case HB_SCRIPT_BUHID:
     case HB_SCRIPT_HANUNOO:
-    case HB_SCRIPT_MEETEI_MAYEK:
+
+    /* Unicode-5.1 additions */
     case HB_SCRIPT_SAURASHTRA:
 
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_MEETEI_MAYEK:
+
+    /* Unicode-6.0 additions */
+    case HB_SCRIPT_BATAK:
+    case HB_SCRIPT_BRAHMI:
+
+
     /* Simple */
-    case HB_SCRIPT_KAYAH_LI:
+
+    /* Unicode-1.1 additions */
+    /* TODO These two need their own shaper I guess? */
     case HB_SCRIPT_LAO:
-    case HB_SCRIPT_LIMBU:
-    case HB_SCRIPT_PHAGS_PA:
-    case HB_SCRIPT_SYLOTI_NAGRI:
+    case HB_SCRIPT_THAI:
+
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+
+    /* Unicode-3.2 additions */
     case HB_SCRIPT_TAGALOG:
     case HB_SCRIPT_TAGBANWA:
+
+    /* Unicode-4.0 additions */
+    case HB_SCRIPT_LIMBU:
     case HB_SCRIPT_TAI_LE:
+
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_SYLOTI_NAGRI:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_PHAGS_PA:
+
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_KAYAH_LI:
+
+    /* Unicode-5.2 additions */
     case HB_SCRIPT_TAI_VIET:
-    case HB_SCRIPT_THAI:
-    case HB_SCRIPT_TIBETAN:
+
 
     /* May need Indic treatment in the future? */
+
+    /* Unicode-3.0 additions */
     case HB_SCRIPT_MYANMAR:
+
+
 #endif
 
-    case HB_SCRIPT_BALINESE:
+    /* Unicode-1.1 additions */
     case HB_SCRIPT_BENGALI:
-    case HB_SCRIPT_BUGINESE:
-    case HB_SCRIPT_BUHID:
-    case HB_SCRIPT_CHAM:
     case HB_SCRIPT_DEVANAGARI:
     case HB_SCRIPT_GUJARATI:
     case HB_SCRIPT_GURMUKHI:
+    case HB_SCRIPT_KANNADA:
+    case HB_SCRIPT_MALAYALAM:
+    case HB_SCRIPT_ORIYA:
+    case HB_SCRIPT_TAMIL:
+    case HB_SCRIPT_TELUGU:
+
+    /* Unicode-3.0 additions */
+    case HB_SCRIPT_KHMER:
+    case HB_SCRIPT_SINHALA:
+
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_BUGINESE:
+    case HB_SCRIPT_KHAROSHTHI:
+    case HB_SCRIPT_NEW_TAI_LUE:
+
+    /* Unicode-5.0 additions */
+    case HB_SCRIPT_BALINESE:
+
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_CHAM:
+    case HB_SCRIPT_LEPCHA:
+    case HB_SCRIPT_REJANG:
+    case HB_SCRIPT_SUNDANESE:
+
+    /* Unicode-5.2 additions */
     case HB_SCRIPT_JAVANESE:
     case HB_SCRIPT_KAITHI:
-    case HB_SCRIPT_KANNADA:
-    case HB_SCRIPT_KHAROSHTHI:
-    case HB_SCRIPT_KHMER:
-    case HB_SCRIPT_LEPCHA:
-    case HB_SCRIPT_MALAYALAM:
-    case HB_SCRIPT_NEW_TAI_LUE:
-    case HB_SCRIPT_ORIYA:
-    case HB_SCRIPT_REJANG:
-    case HB_SCRIPT_SINHALA:
-    case HB_SCRIPT_SUNDANESE:
     case HB_SCRIPT_TAI_THAM:
-    case HB_SCRIPT_TAMIL:
-    case HB_SCRIPT_TELUGU:
+
+    /* Unicode-6.1 additions */
+    case HB_SCRIPT_CHAKMA:
+    case HB_SCRIPT_SHARADA:
+    case HB_SCRIPT_TAKRI:
+
       return hb_ot_complex_shaper_indic;
-
-    /* ^--- Add new shapers here */
   }
 }
 
 
 
 /*
  * collect_features()
  *
@@ -165,64 +242,65 @@ hb_ot_shape_complex_collect_features (hb
     case hb_ot_complex_shaper_##name:	_hb_ot_shape_complex_collect_features_##name (map, props); return;
     HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
   }
 }
 
 
 /*
- * prefer_decomposed()
+ * normalization_preference()
  *
  * Called during shape_execute().
  *
  * Shapers should return TRUE if it prefers decomposed (NFD) input rather than precomposed (NFC).
  */
 
-typedef bool hb_ot_shape_complex_prefer_decomposed_func_t (void);
+typedef hb_ot_shape_normalization_mode_t hb_ot_shape_complex_normalization_preference_func_t (void);
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-  HB_INTERNAL hb_ot_shape_complex_prefer_decomposed_func_t _hb_ot_shape_complex_prefer_decomposed_##name;
+  HB_INTERNAL hb_ot_shape_complex_normalization_preference_func_t _hb_ot_shape_complex_normalization_preference_##name;
   HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
 
-static inline bool
-hb_ot_shape_complex_prefer_decomposed (hb_ot_complex_shaper_t shaper)
+static inline hb_ot_shape_normalization_mode_t
+hb_ot_shape_complex_normalization_preference (hb_ot_complex_shaper_t shaper)
 {
   switch (shaper) {
     default:
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-    case hb_ot_complex_shaper_##name:	return _hb_ot_shape_complex_prefer_decomposed_##name ();
+    case hb_ot_complex_shaper_##name:	return _hb_ot_shape_complex_normalization_preference_##name ();
     HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
   }
 }
 
 
 /* setup_masks()
  *
  * Called during shape_execute().
  *
  * Shapers should use map to get feature masks and set on buffer.
  */
 
-typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer);
+typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font);
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
   HB_INTERNAL hb_ot_shape_complex_setup_masks_func_t _hb_ot_shape_complex_setup_masks_##name;
   HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
 
 static inline void
 hb_ot_shape_complex_setup_masks (hb_ot_complex_shaper_t shaper,
 				 hb_ot_map_t *map,
-				 hb_buffer_t *buffer)
+				 hb_buffer_t *buffer,
+				 hb_font_t *font)
 {
   switch (shaper) {
     default:
 #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-    case hb_ot_complex_shaper_##name:	_hb_ot_shape_complex_setup_masks_##name (map, buffer); return;
+    case hb_ot_complex_shaper_##name:	_hb_ot_shape_complex_setup_masks_##name (map, buffer, font); return;
     HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
 #undef HB_COMPLEX_SHAPER_IMPLEMENT
   }
 }
 
 
 
 #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_NORMALIZE_PRIVATE_HH
+#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-font.h"
+#include "hb-buffer.h"
+
+
+enum hb_ot_shape_normalization_mode_t {
+  HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL /* including base-to-base composition */
+};
+
+HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font,
+					 hb_buffer_t *buffer,
+					 hb_ot_shape_normalization_mode_t mode);
+
+#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -19,28 +19,30 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
+#include "hb-ot-shape-normalize-private.hh"
 #include "hb-ot-shape-private.hh"
-#include "hb-ot-shape-complex-private.hh"
 
 
 /*
  * HIGHLEVEL DESIGN:
  *
  * This file exports one main function: _hb_ot_shape_normalize().
  *
  * This function closely reflects the Unicode Normalization Algorithm,
- * yet it's different.  The shaper an either prefer decomposed (NFD) or
- * composed (NFC).
+ * yet it's different.
+ *
+ * Each shaper specifies whether it prefers decomposed (NFD) or composed (NFC).
+ * The logic however tries to use whatever the font can support.
  *
  * In general what happens is that: each grapheme is decomposed in a chain
  * of 1:2 decompositions, marks reordered, and then recomposed if desired,
  * so far it's like Unicode Normalization.  However, the decomposition and
  * recomposition only happens if the font supports the resulting characters.
  *
  * The goals are:
  *
@@ -51,127 +53,132 @@
  *     don't touch 1-character clusters that are supported by the font, even
  *     though their NFC may be different.
  *
  *   - When a font has a precomposed character for a sequence but the 'ccmp'
  *     feature in the font is not adequate, use the precomposed character
  *     which typically has better mark positioning.
  *
  *   - When a font does not support a combining mark, but supports it precomposed
- *     with previous base.  This needs the itemizer to have this knowledge too.
- *     We need ot provide assistance to the itemizer.
+ *     with previous base, use that.  This needs the itemizer to have this
+ *     knowledge too.  We need to provide assistance to the itemizer.
  *
  *   - When a font does not support a character but supports its decomposition,
  *     well, use the decomposition.
  *
  *   - The Indic shaper requests decomposed output.  This will handle splitting
  *     matra for the Indic shaper.
  */
 
+static inline void
+set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  info->general_category() = hb_unicode_general_category (unicode, info->codepoint);
+  info->combining_class() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
+}
+
 static void
-output_glyph (hb_ot_shape_context_t *c,
+output_glyph (hb_font_t *font, hb_buffer_t *buffer,
 	      hb_codepoint_t glyph)
 {
-  hb_buffer_t *buffer = c->buffer;
-
   buffer->output_glyph (glyph);
-  hb_glyph_info_set_unicode_props (&buffer->out_info[buffer->out_len - 1], buffer->unicode);
+  set_unicode_props (&buffer->out_info[buffer->out_len - 1], buffer->unicode);
 }
 
 static bool
-decompose (hb_ot_shape_context_t *c,
+decompose (hb_font_t *font, hb_buffer_t *buffer,
 	   bool shortest,
 	   hb_codepoint_t ab)
 {
   hb_codepoint_t a, b, glyph;
 
-  if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) ||
-      (b && !hb_font_get_glyph (c->font, b, 0, &glyph)))
+  if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) ||
+      (b && !hb_font_get_glyph (font, b, 0, &glyph)))
     return FALSE;
 
-  bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph);
+  bool has_a = hb_font_get_glyph (font, a, 0, &glyph);
   if (shortest && has_a) {
     /* Output a and b */
-    output_glyph (c, a);
+    output_glyph (font, buffer, a);
     if (b)
-      output_glyph (c, b);
+      output_glyph (font, buffer, b);
     return TRUE;
   }
 
-  if (decompose (c, shortest, a)) {
+  if (decompose (font, buffer, shortest, a)) {
     if (b)
-      output_glyph (c, b);
+      output_glyph (font, buffer, b);
     return TRUE;
   }
 
   if (has_a) {
-    output_glyph (c, a);
+    output_glyph (font, buffer, a);
     if (b)
-      output_glyph (c, b);
+      output_glyph (font, buffer, b);
     return TRUE;
   }
 
   return FALSE;
 }
 
 static void
-decompose_current_glyph (hb_ot_shape_context_t *c,
+decompose_current_glyph (hb_font_t *font, hb_buffer_t *buffer,
 			 bool shortest)
 {
-  if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint))
-    c->buffer->skip_glyph ();
+  if (decompose (font, buffer, shortest, buffer->info[buffer->idx].codepoint))
+    buffer->skip_glyph ();
   else
-    c->buffer->next_glyph ();
+    buffer->next_glyph ();
 }
 
 static void
-decompose_single_char_cluster (hb_ot_shape_context_t *c,
+decompose_single_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
 			       bool will_recompose)
 {
   hb_codepoint_t glyph;
 
   /* If recomposing and font supports this, we're good to go */
-  if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) {
-    c->buffer->next_glyph ();
+  if (will_recompose && hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph)) {
+    buffer->next_glyph ();
     return;
   }
 
-  decompose_current_glyph (c, will_recompose);
+  decompose_current_glyph (font, buffer, will_recompose);
 }
 
 static void
-decompose_multi_char_cluster (hb_ot_shape_context_t *c,
+decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
 			      unsigned int end)
 {
   /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
-  for (unsigned int i = c->buffer->idx; i < end; i++)
-    if (unlikely (is_variation_selector (c->buffer->info[i].codepoint))) {
-      while (c->buffer->idx < end)
-	c->buffer->next_glyph ();
+  for (unsigned int i = buffer->idx; i < end; i++)
+    if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))) {
+      while (buffer->idx < end)
+	buffer->next_glyph ();
       return;
     }
 
-  while (c->buffer->idx < end)
-    decompose_current_glyph (c, FALSE);
+  while (buffer->idx < end)
+    decompose_current_glyph (font, buffer, FALSE);
 }
 
 static int
 compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
 {
   unsigned int a = pa->combining_class();
   unsigned int b = pb->combining_class();
 
   return a < b ? -1 : a == b ? 0 : +1;
 }
 
 void
-_hb_ot_shape_normalize (hb_ot_shape_context_t *c)
+_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
+			hb_ot_shape_normalization_mode_t mode)
 {
-  hb_buffer_t *buffer = c->buffer;
-  bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper);
+  bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
   bool has_multichar_clusters = FALSE;
   unsigned int count;
 
   /* We do a fairly straightforward yet custom normalization process in three
    * separate rounds: decompose, reorder, recompose (if desired).  Currently
    * this makes two buffer swaps.  We can make it faster by moving the last
    * two rounds into the inner loop for the first round, but it's more readable
    * this way. */
@@ -184,37 +191,26 @@ void
   for (buffer->idx = 0; buffer->idx < count;)
   {
     unsigned int end;
     for (end = buffer->idx + 1; end < count; end++)
       if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster)
         break;
 
     if (buffer->idx + 1 == end)
-      decompose_single_char_cluster (c, recompose);
+      decompose_single_char_cluster (font, buffer, recompose);
     else {
-      decompose_multi_char_cluster (c, end);
+      decompose_multi_char_cluster (font, buffer, end);
       has_multichar_clusters = TRUE;
     }
   }
   buffer->swap_buffers ();
 
 
-  /* Technically speaking, two characters with ccc=0 may combine.  But all
-   * those cases are in languages that the indic module handles (which expects
-   * decomposed), or in Hangul jamo, which again, we want decomposed anyway.
-   * So we don't bother combining across cluster boundaries.  This is a huge
-   * performance saver if the compose() callback is slow.
-   *
-   * TODO: Am I right about Hangul?  If I am, we should add a Hangul module
-   * that requests decomposed.  If for Hangul we end up wanting composed, we
-   * can do that in the Hangul module.
-   */
-
-  if (!has_multichar_clusters)
+  if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !has_multichar_clusters)
     return; /* Done! */
 
 
   /* Second round, reorder (inplace) */
 
   count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
   {
@@ -249,38 +245,42 @@ void
    * ccc=0 chars with their previous Starter. */
 
   buffer->clear_output ();
   count = buffer->len;
   unsigned int starter = 0;
   buffer->next_glyph ();
   while (buffer->idx < count)
   {
-    if (buffer->info[buffer->idx].combining_class() == 0) {
-      starter = buffer->out_len;
-      buffer->next_glyph ();
+    hb_codepoint_t composed, glyph;
+    if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to
+	 * compose a CCC=0 character with it's preceding starter. */
+	(mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL ||
+	 buffer->info[buffer->idx].combining_class() != 0) &&
+	/* If there's anything between the starter and this char, they should have CCC
+	 * smaller than this character's. */
+	(starter == buffer->out_len - 1 ||
+	 buffer->out_info[buffer->out_len - 1].combining_class() < buffer->info[buffer->idx].combining_class()) &&
+	/* And compose. */
+	hb_unicode_compose (buffer->unicode,
+			    buffer->out_info[starter].codepoint,
+			    buffer->info[buffer->idx].codepoint,
+			    &composed) &&
+	/* And the font has glyph for the composite. */
+	hb_font_get_glyph (font, composed, 0, &glyph))
+    {
+      /* Composes. Modify starter and carry on. */
+      buffer->out_info[starter].codepoint = composed;
+      set_unicode_props (&buffer->out_info[starter], buffer->unicode);
+
+      buffer->skip_glyph ();
       continue;
     }
 
-    hb_codepoint_t composed, glyph;
-    if ((buffer->out_info[buffer->out_len - 1].combining_class() >=
-	 buffer->info[buffer->idx].combining_class()) ||
-	!hb_unicode_compose (c->buffer->unicode,
-			     buffer->out_info[starter].codepoint,
-			     buffer->info[buffer->idx].codepoint,
-			     &composed) ||
-	!hb_font_get_glyph (c->font, composed, 0, &glyph))
-    {
-      /* Blocked, or doesn't compose. */
-      buffer->next_glyph ();
-      continue;
-    }
+    /* Blocked, or doesn't compose. */
+    buffer->next_glyph ();
 
-    /* Composes. Modify starter and carry on. */
-    buffer->out_info[starter].codepoint = composed;
-    hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
-
-    buffer->skip_glyph ();
+    if (buffer->out_info[buffer->out_len - 1].combining_class() == 0)
+      starter = buffer->out_len - 1;
   }
   buffer->swap_buffers ();
 
 }
-
--- a/gfx/harfbuzz/src/hb-ot-shape-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh
@@ -24,134 +24,33 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_SHAPE_PRIVATE_HH
 #define HB_OT_SHAPE_PRIVATE_HH
 
 #include "hb-private.hh"
 
-#include "hb-ot-shape.h"
-
 #include "hb-ot-map-private.hh"
 #include "hb-ot-shape-complex-private.hh"
 
 
-
-enum hb_ot_complex_shaper_t;
-
 struct hb_ot_shape_plan_t
 {
-  friend struct hb_ot_shape_planner_t;
-
   hb_ot_map_t map;
   hb_ot_complex_shaper_t shaper;
 
   hb_ot_shape_plan_t (void) : map () {}
   ~hb_ot_shape_plan_t (void) { map.finish (); }
 
   private:
   NO_COPY (hb_ot_shape_plan_t);
 };
 
-struct hb_ot_shape_planner_t
-{
-  hb_ot_map_builder_t map;
-  hb_ot_complex_shaper_t shaper;
-
-  hb_ot_shape_planner_t (void) : map () {}
-  ~hb_ot_shape_planner_t (void) { map.finish (); }
-
-  inline void compile (hb_face_t *face,
-		       const hb_segment_properties_t *props,
-		       struct hb_ot_shape_plan_t &plan)
-  {
-    plan.shaper = shaper;
-    map.compile (face, props, plan.map);
-  }
-
-  private:
-  NO_COPY (hb_ot_shape_planner_t);
-};
-
-
-struct hb_ot_shape_context_t
-{
-  /* Input to hb_ot_shape_execute() */
-  hb_ot_shape_plan_t *plan;
-  hb_font_t *font;
-  hb_face_t *face;
-  hb_buffer_t  *buffer;
-  const hb_feature_t *user_features;
-  unsigned int        num_user_features;
-
-  /* Transient stuff */
-  hb_direction_t target_direction;
-  hb_bool_t applied_substitute_complex;
-  hb_bool_t applied_position_complex;
-};
 
 
-static inline hb_bool_t
-is_variation_selector (hb_codepoint_t unicode)
-{
-  return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
-		   (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
-		   (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
-}
-
-static inline unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
-				      hb_codepoint_t      unicode)
-{
-  int c = hb_unicode_combining_class (ufuncs, unicode);
-
-  /* For Hebrew, we permute the "fixed-position" classes 10-25 into the order
-   * described in the SBL Hebrew manual http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
-   * (as recommended by http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
-   */
-  static const int permuted_hebrew_classes[25 - 10 + 1] = {
-    /* 10 sheva */        22,
-    /* 11 hataf segol */  15,
-    /* 12 hataf patah */  16,
-    /* 13 hataf qamats */ 17,
-    /* 14 hiriq */        23,
-    /* 15 tsere */        18,
-    /* 16 segol */        19,
-    /* 17 patah */        20,
-    /* 18 qamats */       21,
-    /* 19 holam */        14,
-    /* 20 qubuts */       24,
-    /* 21 dagesh */       12,
-    /* 22 meteg */        25,
-    /* 23 rafe */         13,
-    /* 24 shin dot */     10,
-    /* 25 sin dot */      11,
-  };
-
-  /* Modify the combining-class to suit Arabic better.  See:
-   * http://unicode.org/faq/normalization.html#8
-   * http://unicode.org/faq/normalization.html#9
-   */
-  if (unlikely (hb_in_range<int> (c, 27, 33)))
-    c = c == 33 ? 27 : c + 1;
-  /* The equivalent fix for Hebrew is more complex,
-   * see the SBL Hebrew manual.
-   */
-  else if (unlikely (hb_in_range<int> (c, 10, 25)))
-    c = permuted_hebrew_classes[c - 10];
-
-  return c;
-}
-
-static inline void
-hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
-{
-  info->general_category() = hb_unicode_general_category (unicode, info->codepoint);
-  info->combining_class() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
-}
-
-HB_INTERNAL void _hb_set_unicode_props (hb_buffer_t *buffer);
-
-HB_INTERNAL void _hb_ot_shape_normalize (hb_ot_shape_context_t *c);
-
+HB_INTERNAL hb_bool_t
+_hb_ot_shape (hb_font_t          *font,
+	      hb_buffer_t        *buffer,
+	      const hb_feature_t *features,
+	      unsigned int        num_features);
 
 #endif /* HB_OT_SHAPE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-shape.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape.cc
@@ -22,51 +22,73 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-shape-private.hh"
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-normalize-private.hh"
 
 #include "hb-font-private.hh"
 
 
 
 hb_tag_t common_features[] = {
   HB_TAG('c','c','m','p'),
+  HB_TAG('l','i','g','a'),
   HB_TAG('l','o','c','l'),
   HB_TAG('m','a','r','k'),
   HB_TAG('m','k','m','k'),
   HB_TAG('r','l','i','g'),
 };
 
 hb_tag_t horizontal_features[] = {
   HB_TAG('c','a','l','t'),
   HB_TAG('c','l','i','g'),
   HB_TAG('c','u','r','s'),
   HB_TAG('k','e','r','n'),
-  HB_TAG('l','i','g','a'),
 };
 
 /* Note:
  * Technically speaking, vrt2 and vert are mutually exclusive.
  * According to the spec, valt and vpal are also mutually exclusive.
  * But we apply them all for now.
  */
 hb_tag_t vertical_features[] = {
   HB_TAG('v','a','l','t'),
   HB_TAG('v','e','r','t'),
   HB_TAG('v','k','r','n'),
   HB_TAG('v','p','a','l'),
   HB_TAG('v','r','t','2'),
 };
 
+
+
+struct hb_ot_shape_planner_t
+{
+  hb_ot_map_builder_t map;
+  hb_ot_complex_shaper_t shaper;
+
+  hb_ot_shape_planner_t (void) : map () {}
+  ~hb_ot_shape_planner_t (void) { map.finish (); }
+
+  inline void compile (hb_face_t *face,
+		       const hb_segment_properties_t *props,
+		       struct hb_ot_shape_plan_t &plan)
+  {
+    plan.shaper = shaper;
+    map.compile (face, props, plan.map);
+  }
+
+  private:
+  NO_COPY (hb_ot_shape_planner_t);
+};
+
 static void
 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
 			      const hb_segment_properties_t  *props,
 			      const hb_feature_t             *user_features,
 			      unsigned int                    num_user_features)
 {
   switch (props->direction) {
     case HB_DIRECTION_LTR:
@@ -103,23 +125,38 @@ hb_ot_shape_collect_features (hb_ot_shap
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
     planner->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
   }
 }
 
 
+struct hb_ot_shape_context_t
+{
+  /* Input to hb_ot_shape_execute() */
+  hb_ot_shape_plan_t *plan;
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t  *buffer;
+  const hb_feature_t *user_features;
+  unsigned int        num_user_features;
+
+  /* Transient stuff */
+  hb_direction_t target_direction;
+  hb_bool_t applied_position_complex;
+};
+
 static void
 hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
 {
   hb_mask_t global_mask = c->plan->map.get_global_mask ();
   c->buffer->reset_masks (global_mask);
 
-  hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer);
+  hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c->font);
 
   for (unsigned int i = 0; i < c->num_user_features; i++)
   {
     const hb_feature_t *feature = &c->user_features[i];
     if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
       unsigned int shift;
       hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
       c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
@@ -127,22 +164,29 @@ hb_ot_shape_setup_masks (hb_ot_shape_con
   }
 }
 
 
 /* Main shaper */
 
 /* Prepare */
 
-void
-_hb_set_unicode_props (hb_buffer_t *buffer)
+static inline void
+set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  info->general_category() = hb_unicode_general_category (unicode, info->codepoint);
+  info->combining_class() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
+}
+
+static void
+hb_set_unicode_props (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
-  for (unsigned int i = 1; i < count; i++)
-    hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
+  for (unsigned int i = 0; i < count; i++)
+    set_unicode_props (&buffer->info[i], buffer->unicode);
 }
 
 static void
 hb_form_clusters (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
   for (unsigned int i = 1; i < count; i++)
     if (FLAG (buffer->info[i].general_category()) &
@@ -200,17 +244,17 @@ hb_map_glyphs (hb_font_t    *font,
 
   if (unlikely (!buffer->len))
     return;
 
   buffer->clear_output ();
 
   unsigned int count = buffer->len - 1;
   for (buffer->idx = 0; buffer->idx < count;) {
-    if (unlikely (is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) {
+    if (unlikely (_hb_unicode_is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) {
       hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, buffer->info[buffer->idx + 1].codepoint, &glyph);
       buffer->replace_glyph (glyph);
       buffer->skip_glyph ();
     } else {
       hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph);
       buffer->replace_glyph (glyph);
     }
   }
@@ -231,30 +275,23 @@ hb_substitute_default (hb_ot_shape_conte
   hb_map_glyphs (c->font, c->buffer);
 }
 
 static void
 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
   if (hb_ot_layout_has_substitution (c->face)) {
     c->plan->map.substitute (c->face, c->buffer);
-    c->applied_substitute_complex = TRUE;
   }
 
   hb_ot_layout_substitute_finish (c->buffer);
 
   return;
 }
 
-static void
-hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
-{
-  /* TODO Arabic */
-}
-
 
 /* Position */
 
 static void
 hb_position_default (hb_ot_shape_context_t *c)
 {
   hb_ot_layout_position_start (c->buffer);
 
@@ -294,46 +331,25 @@ hb_ot_position_complex (hb_ot_shape_cont
 						   HB_DIRECTION_LTR,
 						   &c->buffer->pos[i].x_offset,
 						   &c->buffer->pos[i].y_offset);
     }
 
     c->applied_position_complex = TRUE;
   }
 
-  hb_ot_layout_position_finish (c->face, c->buffer);
+  hb_ot_layout_position_finish (c->buffer);
 
   return;
 }
 
 static void
-hb_position_complex_fallback (hb_ot_shape_context_t *c)
+hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
 {
-  unsigned int count = c->buffer->len;
-  if (c->buffer->props.direction == HB_DIRECTION_RTL) {
-    for (unsigned int i = 1; i < count; i++) {
-      unsigned int gen_cat = c->buffer->info[i].general_category();
-      if ((1<<gen_cat) & ((1<<HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)|
-                          (1<<HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)|
-                          (1<<HB_UNICODE_GENERAL_CATEGORY_FORMAT))) {
-        c->buffer->pos[i].x_advance = 0;
-      }
-    }
-  } else {
-    for (unsigned int i = 1; i < count; i++) {
-      unsigned int gen_cat = c->buffer->info[i].general_category();
-      if ((1<<gen_cat) & ((1<<HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)|
-                          (1<<HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK)|
-                          (1<<HB_UNICODE_GENERAL_CATEGORY_FORMAT))) {
-        hb_glyph_position_t& pos = c->buffer->pos[i];
-        pos.x_offset = -pos.x_advance;
-        pos.x_advance = 0;
-      }
-    }
-  }
+  /* TODO Mark pos */
 }
 
 static void
 hb_truetype_kern (hb_ot_shape_context_t *c)
 {
   /* TODO Check for kern=0 */
   unsigned int count = c->buffer->len;
   for (unsigned int i = 1; i < count; i++) {
@@ -372,34 +388,31 @@ hb_ot_shape_execute_internal (hb_ot_shap
   c->buffer->deallocate_var_all ();
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
 
   HB_BUFFER_ALLOCATE_VAR (c->buffer, general_category);
   HB_BUFFER_ALLOCATE_VAR (c->buffer, combining_class);
 
-  _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class */
+  hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class */
 
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
 
-  _hb_ot_shape_normalize (c);
+  _hb_ot_shape_normalize (c->font, c->buffer, hb_ot_shape_complex_normalization_preference (c->plan->shaper));
 
   hb_ot_shape_setup_masks (c);
 
   /* SUBSTITUTE */
   {
     hb_substitute_default (c);
 
     hb_ot_substitute_complex (c);
-
-    if (!c->applied_substitute_complex)
-      hb_substitute_complex_fallback (c);
   }
 
   /* POSITION */
   {
     hb_position_default (c);
 
     hb_ot_position_complex (c);
 
@@ -426,16 +439,18 @@ static void
 hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
 			   hb_face_t                *face,
 			   const hb_segment_properties_t  *props,
 			   const hb_feature_t       *user_features,
 			   unsigned int              num_user_features)
 {
   hb_ot_shape_planner_t planner;
 
+  assert (HB_DIRECTION_IS_VALID (props->direction));
+
   planner.shaper = hb_ot_shape_complex_categorize (props);
 
   hb_ot_shape_collect_features (&planner, props, user_features, num_user_features);
 
   planner.compile (face, props, *plan);
 }
 
 static void
@@ -445,25 +460,22 @@ hb_ot_shape_execute (hb_ot_shape_plan_t 
 		     const hb_feature_t *user_features,
 		     unsigned int        num_user_features)
 {
   hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_user_features};
   hb_ot_shape_execute_internal (&c);
 }
 
 hb_bool_t
-hb_ot_shape (hb_font_t          *font,
-	     hb_buffer_t        *buffer,
-	     const hb_feature_t *features,
-	     unsigned int        num_features,
-	     const char * const *shaper_options)
+_hb_ot_shape (hb_font_t          *font,
+	      hb_buffer_t        *buffer,
+	      const hb_feature_t *features,
+	      unsigned int        num_features)
 {
   hb_ot_shape_plan_t plan;
 
   buffer->guess_properties ();
 
   hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
   hb_ot_shape_execute (&plan, font, buffer, features, num_features);
 
   return TRUE;
 }
-
-
--- a/gfx/harfbuzz/src/hb-ot-tag.h
+++ b/gfx/harfbuzz/src/hb-ot-tag.h
@@ -19,20 +19,24 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
 #ifndef HB_OT_TAG_H
 #define HB_OT_TAG_H
 
-#include "hb-common.h"
+#include "hb.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_OT_TAG_DEFAULT_SCRIPT	HB_TAG ('D', 'F', 'L', 'T')
 #define HB_OT_TAG_DEFAULT_LANGUAGE	HB_TAG ('d', 'f', 'l', 't')
 
 void
--- a/gfx/harfbuzz/src/hb-ot.h
+++ b/gfx/harfbuzz/src/hb-ot.h
@@ -21,19 +21,20 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_H
 #define HB_OT_H
+#define HB_OT_H_IN
 
 #include "hb.h"
 
 #include "hb-ot-layout.h"
-#include "hb-ot-shape.h"
 #include "hb-ot-tag.h"
 
 HB_BEGIN_DECLS
 HB_END_DECLS
 
+#undef HB_OT_H_IN
 #endif /* HB_OT_H */
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -28,17 +28,20 @@
 
 #ifndef HB_PRIVATE_HH
 #define HB_PRIVATE_HH
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "hb-common.h"
+#include "hb.h"
+#include "hb-ot.h"
+#define HB_H_IN
+#define HB_OT_H_IN
 
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <assert.h>
 
 /* We only use these two for debug output.  However, the debug code is
  * always seen by the compiler (and optimized out in non-debug builds.
@@ -432,16 +435,24 @@ struct hb_lockable_set_t
 /* Big-endian handling */
 
 static inline uint16_t hb_be_uint16 (const uint16_t v)
 {
   const uint8_t *V = (const uint8_t *) &v;
   return (uint16_t) (V[0] << 8) + V[1];
 }
 
+/* Note, of the following macros, uint16_get is the one called many many times.
+ * If there is any optimizations to be done, it's in that macro.  However, I
+ * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
+ * results in a single ror instruction, does NOT speed this up.  In fact, it
+ * resulted in a minor slowdown.  At any rate, note that v may not be correctly
+ * aligned, so I think the current implementation is optimal.
+ */
+
 #define hb_be_uint16_put(v,V)	HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
 #define hb_be_uint16_get(v)	(uint16_t) ((v[0] << 8) + v[1])
 #define hb_be_uint16_eq(a,b)	(a[0] == b[0] && a[1] == b[1])
 
 #define hb_be_uint32_put(v,V)	HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
 #define hb_be_uint32_get(v)	(uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
 #define hb_be_uint32_eq(a,b)	(a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
 
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -26,40 +26,39 @@
 
 #include "hb-private.hh"
 
 #include "hb-shape.h"
 
 #include "hb-buffer-private.hh"
 
 #ifdef HAVE_GRAPHITE
-#include "hb-graphite2.h"
+#include "hb-graphite2-private.hh"
 #endif
 #ifdef HAVE_UNISCRIBE
-# include "hb-uniscribe.h"
+# include "hb-uniscribe-private.hh"
 #endif
 #ifdef HAVE_OT
-# include "hb-ot-shape.h"
+# include "hb-ot-shape-private.hh"
 #endif
 #include "hb-fallback-shape-private.hh"
 
 typedef hb_bool_t (*hb_shape_func_t) (hb_font_t          *font,
 				      hb_buffer_t        *buffer,
 				      const hb_feature_t *features,
-				      unsigned int        num_features,
-				      const char * const *shaper_options);
+				      unsigned int        num_features);
 
-#define HB_SHAPER_IMPLEMENT(name) {#name, hb_##name##_shape}
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}
 static struct hb_shaper_pair_t {
   char name[16];
   hb_shape_func_t func;
 } shapers[] = {
   /* v--- Add new shapers in the right place here */
 #ifdef HAVE_GRAPHITE
-  HB_SHAPER_IMPLEMENT (graphite),
+  HB_SHAPER_IMPLEMENT (graphite2),
 #endif
 #ifdef HAVE_UNISCRIBE
   HB_SHAPER_IMPLEMENT (uniscribe),
 #endif
 #ifdef HAVE_OT
   HB_SHAPER_IMPLEMENT (ot),
 #endif
   HB_SHAPER_IMPLEMENT (fallback) /* should be last */
@@ -115,41 +114,36 @@ hb_shape_list_shapers (void)
   return static_shaper_list.shaper_list;
 }
 
 hb_bool_t
 hb_shape_full (hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features,
-	       const char * const *shaper_options,
 	       const char * const *shaper_list)
 {
   if (likely (!shaper_list)) {
     for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++)
-      if (likely (shapers[i].func (font, buffer,
-				   features, num_features,
-				   shaper_options)))
+      if (likely (shapers[i].func (font, buffer, features, num_features)))
         return TRUE;
   } else {
     while (*shaper_list) {
       for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++)
 	if (0 == strcmp (*shaper_list, shapers[i].name)) {
-	  if (likely (shapers[i].func (font, buffer,
-				       features, num_features,
-				       shaper_options)))
+	  if (likely (shapers[i].func (font, buffer, features, num_features)))
 	    return TRUE;
 	  break;
 	}
       shaper_list++;
     }
   }
   return FALSE;
 }
 
 void
 hb_shape (hb_font_t           *font,
 	  hb_buffer_t         *buffer,
 	  const hb_feature_t  *features,
 	  unsigned int         num_features)
 {
-  hb_shape_full (font, buffer, features, num_features, NULL, NULL);
+  hb_shape_full (font, buffer, features, num_features, NULL);
 }
--- a/gfx/harfbuzz/src/hb-shape.h
+++ b/gfx/harfbuzz/src/hb-shape.h
@@ -19,16 +19,20 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_SHAPE_H
 #define HB_SHAPE_H
 
 #include "hb-common.h"
 #include "hb-buffer.h"
 #include "hb-font.h"
 
 HB_BEGIN_DECLS
@@ -48,17 +52,16 @@ hb_shape (hb_font_t           *font,
 	  const hb_feature_t  *features,
 	  unsigned int         num_features);
 
 hb_bool_t
 hb_shape_full (hb_font_t          *font,
 	       hb_buffer_t        *buffer,
 	       const hb_feature_t *features,
 	       unsigned int        num_features,
-	       const char * const *shaper_options,
 	       const char * const *shaper_list);
 
 const char **
 hb_shape_list_shapers (void);
 
 
 HB_END_DECLS
 
--- a/gfx/harfbuzz/src/hb-unicode-private.hh
+++ b/gfx/harfbuzz/src/hb-unicode-private.hh
@@ -97,11 +97,22 @@ extern HB_INTERNAL hb_unicode_funcs_t _h
 extern HB_INTERNAL hb_unicode_funcs_t _hb_icu_unicode_funcs;
 #define _hb_unicode_funcs_default _hb_icu_unicode_funcs
 #else
 extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil;
 #define _hb_unicode_funcs_default _hb_unicode_funcs_nil
 #endif
 
 
+HB_INTERNAL unsigned int
+_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
+				      hb_codepoint_t      unicode);
+
+static inline hb_bool_t
+_hb_unicode_is_variation_selector (hb_codepoint_t unicode)
+{
+  return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
+		   (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
+		   (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
+}
 
 
 #endif /* HB_UNICODE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-unicode.cc
+++ b/gfx/harfbuzz/src/hb-unicode.cc
@@ -266,8 +266,63 @@ hb_unicode_decompose (hb_unicode_funcs_t
 		      hb_codepoint_t      ab,
 		      hb_codepoint_t     *a,
 		      hb_codepoint_t     *b)
 {
   *a = ab; *b = 0;
   return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose);
 }
 
+
+
+unsigned int
+_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
+				      hb_codepoint_t      unicode)
+{
+  int c = hb_unicode_combining_class (ufuncs, unicode);
+
+  if (unlikely (hb_in_range<int> (c, 27, 33)))
+  {
+    /* Modify the combining-class to suit Arabic better.  See:
+     * http://unicode.org/faq/normalization.html#8
+     * http://unicode.org/faq/normalization.html#9
+     */
+    c = c == 33 ? 27 : c + 1;
+  }
+  else if (unlikely (hb_in_range<int> (c, 10, 25)))
+  {
+    /* The equivalent fix for Hebrew is more complex.
+     *
+     * We permute the "fixed-position" classes 10-25 into the order
+     * described in the SBL Hebrew manual:
+     *
+     * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
+     *
+     * (as recommended by:
+     *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
+     *
+     * More details here:
+     * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
+     */
+    static const int permuted_hebrew_classes[25 - 10 + 1] = {
+      /* 10 sheva */        22,
+      /* 11 hataf segol */  15,
+      /* 12 hataf patah */  16,
+      /* 13 hataf qamats */ 17,
+      /* 14 hiriq */        23,
+      /* 15 tsere */        18,
+      /* 16 segol */        19,
+      /* 17 patah */        20,
+      /* 18 qamats */       21,
+      /* 19 holam */        14,
+      /* 20 qubuts */       24,
+      /* 21 dagesh */       12,
+      /* 22 meteg */        25,
+      /* 23 rafe */         13,
+      /* 24 shin dot */     10,
+      /* 25 sin dot */      11,
+    };
+    c = permuted_hebrew_classes[c - 10];
+  }
+
+  return c;
+}
+
--- a/gfx/harfbuzz/src/hb-unicode.h
+++ b/gfx/harfbuzz/src/hb-unicode.h
@@ -23,16 +23,20 @@
  * 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
  * Codethink Author(s): Ryan Lortie
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_UNICODE_H
 #define HB_UNICODE_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-uniscribe-private.hh
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_UNISCRIBE_PRIVATE_HH
+#define HB_UNISCRIBE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-uniscribe.h"
+
+
+HB_INTERNAL hb_bool_t
+_hb_uniscribe_shape (hb_font_t          *font,
+		     hb_buffer_t        *buffer,
+		     const hb_feature_t *features,
+		     unsigned int        num_features);
+
+
+#endif /* HB_UNISCRIBE_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-uniscribe.cc
+++ b/gfx/harfbuzz/src/hb-uniscribe.cc
@@ -218,21 +218,20 @@ hb_uniscribe_font_get_hfont (hb_font_t *
   hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
   if (unlikely (!font_data))
     return 0;
   return font_data->hfont;
 }
 
 
 hb_bool_t
-hb_uniscribe_shape (hb_font_t          *font,
-		    hb_buffer_t        *buffer,
-		    const hb_feature_t *features,
-		    unsigned int        num_features,
-		    const char * const *shaper_options)
+_hb_uniscribe_shape (hb_font_t          *font,
+		     hb_buffer_t        *buffer,
+		     const hb_feature_t *features,
+		     unsigned int        num_features)
 {
   buffer->guess_properties ();
 
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
     return FALSE; \
   } HB_STMT_END;
--- a/gfx/harfbuzz/src/hb-uniscribe.h
+++ b/gfx/harfbuzz/src/hb-uniscribe.h
@@ -22,32 +22,24 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_UNISCRIBE_H
 #define HB_UNISCRIBE_H
 
-#include "hb-common.h"
-#include "hb-shape.h"
+#include "hb.h"
 
 #define _WIN32_WINNT 0x0500
 #include <windows.h>
 
 HB_BEGIN_DECLS
 
 
-hb_bool_t
-hb_uniscribe_shape (hb_font_t          *font,
-		    hb_buffer_t        *buffer,
-		    const hb_feature_t *features,
-		    unsigned int        num_features,
-		    const char * const *shaper_options);
-
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font);
 
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font);
 
 
 HB_END_DECLS
--- a/gfx/harfbuzz/src/hb-version.h
+++ b/gfx/harfbuzz/src/hb-version.h
@@ -19,16 +19,20 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_VERSION_H
 #define HB_VERSION_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
--- a/gfx/harfbuzz/src/hb-version.h.in
+++ b/gfx/harfbuzz/src/hb-version.h.in
@@ -19,16 +19,20 @@
  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
 #ifndef HB_VERSION_H
 #define HB_VERSION_H
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-warning.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-mutex-private.hh"
+#include "hb-object-private.hh"
+
+
+#if !defined(HB_NO_MT) && defined(HB_ATOMIC_INT_NIL)
+#ifdef _MSC_VER
+#pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe")
+#else
+#warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe"
+#endif
+#endif
+
+#if !defined(HB_NO_MT) && defined(HB_MUTEX_IMPL_NIL)
+#ifdef _MSC_VER
+#pragma message("Could not find any system to define mutex macros, library will NOT be thread-safe")
+#else
+#warning "Could not find any system to define mutex macros, library will NOT be thread-safe"
+#endif
+#endif
+
+#if !defined(HB_NO_MT) && (defined(HB_ATOMIC_INT_NIL) || defined(HB_MUTEX_IMPL_NIL))
+#ifdef _MSC_VER
+#pragma message("To suppress these warnings, define HB_NO_MT")
+#else
+#warning "To suppress these warnings, define HB_NO_MT"
+#endif
+#endif
--- a/gfx/harfbuzz/src/hb.h
+++ b/gfx/harfbuzz/src/hb.h
@@ -21,21 +21,23 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_H
 #define HB_H
+#define HB_H_IN
 
 #include "hb-blob.h"
 #include "hb-buffer.h"
 #include "hb-common.h"
 #include "hb-font.h"
 #include "hb-shape.h"
 #include "hb-unicode.h"
 #include "hb-version.h"
 
 HB_BEGIN_DECLS
 HB_END_DECLS
 
+#undef HB_H_IN
 #endif /* HB_H */
--- a/gfx/thebes/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -42,17 +42,17 @@
 #include "gfxGraphiteShaper.h"
 #endif
 #include "gfxDWriteFontList.h"
 #include "gfxContext.h"
 #include <dwrite.h>
 
 #include "gfxDWriteTextAnalysis.h"
 
-#include "harfbuzz/hb-blob.h"
+#include "harfbuzz/hb.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
 
 using namespace mozilla::gfx;
 
 // This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
 // but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -37,17 +37,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
-#include "harfbuzz/hb-blob.h"
+#include "harfbuzz/hb.h"
 
 gfxFT2FontBase::gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
                                gfxFontEntry *aFontEntry,
                                const gfxFontStyle *aFontStyle)
     : gfxFont(aFontEntry, aFontStyle, kAntialiasDefault, aScaledFont),
       mSpaceGlyph(0),
       mHasMetrics(false)
 {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -69,17 +69,17 @@
 #include "nsStyleConsts.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 
 #include "cairo.h"
 #include "gfxFontTest.h"
 
-#include "harfbuzz/hb-blob.h"
+#include "harfbuzz/hb.h"
 
 #include "nsCRT.h"
 #include "sampler.h"
 
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -46,17 +46,17 @@
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxGraphiteShaper.h"
 #include "gfxFontUtils.h"
 
 #include "graphite2/Font.h"
 #include "graphite2/Segment.h"
 
-#include "harfbuzz/hb-blob.h"
+#include "harfbuzz/hb.h"
 
 #include "cairo.h"
 
 #include "nsUnicodeRange.h"
 #include "nsCRT.h"
 
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -48,17 +48,17 @@
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxFontUtils.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "nsUnicodeNormalizer.h"
 
-#include "harfbuzz/hb-unicode.h"
+#include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 
 #include "cairo.h"
 
 #include "nsCRT.h"
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -58,18 +58,18 @@
 #include "gfxPlatformGtk.h"
 #endif
 #ifdef MOZ_WIDGET_QT
 #include "gfxQtPlatform.h"
 #endif
 #include "gfxPangoFonts.h"
 #include "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
-#include "harfbuzz/hb-unicode.h"
-#include "harfbuzz/hb-ot-tag.h"
+#include "harfbuzz/hb.h"
+#include "harfbuzz/hb-ot.h"
 #include "gfxHarfBuzzShaper.h"
 #ifdef MOZ_GRAPHITE
 #include "gfxGraphiteShaper.h"
 #endif
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "gfxFontconfigUtils.h"
 #include "gfxUserFontSet.h"
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -58,17 +58,17 @@
 #endif
 
 #include "nsGkAtoms.h"
 #include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxUserFontSet.h"
 #include "nsUnicodeProperties.h"
-#include "harfbuzz/hb-unicode.h"
+#include "harfbuzz/hb.h"
 #ifdef MOZ_GRAPHITE
 #include "gfxGraphiteShaper.h"
 #endif
 
 #include "nsUnicodeRange.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 #include "nsUnicharUtilCIID.h"
--- a/intl/unicharutil/util/nsUnicodePropertyData.cpp
+++ b/intl/unicharutil/util/nsUnicodePropertyData.cpp
@@ -70,17 +70,17 @@ for the Unicode Character Database (UCD)
 # HangulSyllableType-6.1.0.txt
 # Date: 2011-08-25, 00:02:18 GMT [MD]
 
  *
  * * * * * This file contains MACHINE-GENERATED DATA, do not edit! * * * * *
  */
 
 #include "mozilla/StandardInteger.h"
-#include "harfbuzz/hb-common.h"
+#include "harfbuzz/hb.h"
 
 static const PRUint32 sScriptCodeToTag[] = {
   HB_TAG('Z','y','y','y'),
   HB_TAG('Z','i','n','h'),
   HB_TAG('A','r','a','b'),
   HB_TAG('A','r','m','n'),
   HB_TAG('B','e','n','g'),
   HB_TAG('B','o','p','o'),