Bug 1467108 - Update HarfBuzz to version 1.8.1. r=jfkthame
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 06 Jun 2018 17:08:29 -0400
changeset 424297 4af580347b1c655f23efc2924e96ddd88b0dbaca
parent 424296 2259143ecb07731b4b3c8eca8df5024251ffaf97
child 424298 e82cf1aca043841a96636e9d4be63d03eab80ad9
push id104762
push userryanvm@gmail.com
push dateThu, 28 Jun 2018 17:52:19 +0000
treeherdermozilla-inbound@4af580347b1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1467108
milestone63.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 1467108 - Update HarfBuzz to version 1.8.1. r=jfkthame
gfx/harfbuzz/Makefile.am
gfx/harfbuzz/NEWS
gfx/harfbuzz/README
gfx/harfbuzz/README-mozilla
gfx/harfbuzz/TODO
gfx/harfbuzz/configure.ac
gfx/harfbuzz/src/Makefile.am
gfx/harfbuzz/src/Makefile.sources
gfx/harfbuzz/src/check-symbols.sh
gfx/harfbuzz/src/dev-run.sh
gfx/harfbuzz/src/dump-emoji.cc
gfx/harfbuzz/src/dump-fon.cc
gfx/harfbuzz/src/gen-arabic-table.py
gfx/harfbuzz/src/gen-def.py
gfx/harfbuzz/src/gen-indic-table.py
gfx/harfbuzz/src/gen-unicode-ranges.py
gfx/harfbuzz/src/gen-use-table.py
gfx/harfbuzz/src/harfbuzz-icu.pc
gfx/harfbuzz/src/harfbuzz-subset.pc
gfx/harfbuzz/src/harfbuzz.pc
gfx/harfbuzz/src/hb-aat-fmtx-table.hh
gfx/harfbuzz/src/hb-aat-gcid-table.hh
gfx/harfbuzz/src/hb-aat-layout-ankr-table.hh
gfx/harfbuzz/src/hb-aat-layout-bsln-table.hh
gfx/harfbuzz/src/hb-aat-layout-common-private.hh
gfx/harfbuzz/src/hb-aat-layout-feat-table.hh
gfx/harfbuzz/src/hb-aat-layout-kerx-table.hh
gfx/harfbuzz/src/hb-aat-layout-morx-table.hh
gfx/harfbuzz/src/hb-aat-layout-trak-table.hh
gfx/harfbuzz/src/hb-aat-layout.cc
gfx/harfbuzz/src/hb-aat-ltag-table.hh
gfx/harfbuzz/src/hb-atomic-private.hh
gfx/harfbuzz/src/hb-blob-private.hh
gfx/harfbuzz/src/hb-blob.cc
gfx/harfbuzz/src/hb-blob.h
gfx/harfbuzz/src/hb-buffer-deserialize-json.hh
gfx/harfbuzz/src/hb-buffer-deserialize-json.rl
gfx/harfbuzz/src/hb-buffer-deserialize-text.hh
gfx/harfbuzz/src/hb-buffer-deserialize-text.rl
gfx/harfbuzz/src/hb-buffer-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-common.cc
gfx/harfbuzz/src/hb-common.h
gfx/harfbuzz/src/hb-coretext.cc
gfx/harfbuzz/src/hb-directwrite.cc
gfx/harfbuzz/src/hb-directwrite.h
gfx/harfbuzz/src/hb-dsalgs.hh
gfx/harfbuzz/src/hb-face.cc
gfx/harfbuzz/src/hb-face.h
gfx/harfbuzz/src/hb-font-private.hh
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-graphite2.h
gfx/harfbuzz/src/hb-icu.cc
gfx/harfbuzz/src/hb-map-private.hh
gfx/harfbuzz/src/hb-map.cc
gfx/harfbuzz/src/hb-map.h
gfx/harfbuzz/src/hb-mutex-private.hh
gfx/harfbuzz/src/hb-object-private.hh
gfx/harfbuzz/src/hb-open-file-private.hh
gfx/harfbuzz/src/hb-open-type-private.hh
gfx/harfbuzz/src/hb-ot-cmap-table.hh
gfx/harfbuzz/src/hb-ot-color-cbdt-table.hh
gfx/harfbuzz/src/hb-ot-color-colr-table.hh
gfx/harfbuzz/src/hb-ot-color-cpal-table.hh
gfx/harfbuzz/src/hb-ot-color-sbix-table.hh
gfx/harfbuzz/src/hb-ot-color-svg-table.hh
gfx/harfbuzz/src/hb-ot-color.cc
gfx/harfbuzz/src/hb-ot-font.cc
gfx/harfbuzz/src/hb-ot-glyf-table.hh
gfx/harfbuzz/src/hb-ot-hdmx-table.hh
gfx/harfbuzz/src/hb-ot-head-table.hh
gfx/harfbuzz/src/hb-ot-hhea-table.hh
gfx/harfbuzz/src/hb-ot-hmtx-table.hh
gfx/harfbuzz/src/hb-ot-kern-table.hh
gfx/harfbuzz/src/hb-ot-layout-base-table.hh
gfx/harfbuzz/src/hb-ot-layout-common-private.hh
gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-layout.cc
gfx/harfbuzz/src/hb-ot-layout.h
gfx/harfbuzz/src/hb-ot-map-private.hh
gfx/harfbuzz/src/hb-ot-map.cc
gfx/harfbuzz/src/hb-ot-math-table.hh
gfx/harfbuzz/src/hb-ot-math.cc
gfx/harfbuzz/src/hb-ot-maxp-table.hh
gfx/harfbuzz/src/hb-ot-name-table.hh
gfx/harfbuzz/src/hb-ot-os2-table.hh
gfx/harfbuzz/src/hb-ot-os2-unicode-ranges.hh
gfx/harfbuzz/src/hb-ot-post-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-hangul.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-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
gfx/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-khmer-machine.rl
gfx/harfbuzz/src/hb-ot-shape-complex-khmer.cc
gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.rl
gfx/harfbuzz/src/hb-ot-shape-complex-use-private.hh
gfx/harfbuzz/src/hb-ot-shape-complex-use-table.cc
gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
gfx/harfbuzz/src/hb-ot-shape-fallback.cc
gfx/harfbuzz/src/hb-ot-shape-normalize.cc
gfx/harfbuzz/src/hb-ot-shape-private.hh
gfx/harfbuzz/src/hb-ot-shape.cc
gfx/harfbuzz/src/hb-ot-tag.cc
gfx/harfbuzz/src/hb-ot-var-avar-table.hh
gfx/harfbuzz/src/hb-ot-var-fvar-table.hh
gfx/harfbuzz/src/hb-ot-var-hvar-table.hh
gfx/harfbuzz/src/hb-ot-var-mvar-table.hh
gfx/harfbuzz/src/hb-ot-var.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-set-private.hh
gfx/harfbuzz/src/hb-set.cc
gfx/harfbuzz/src/hb-set.h
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shaper.cc
gfx/harfbuzz/src/hb-static.cc
gfx/harfbuzz/src/hb-string-array.hh
gfx/harfbuzz/src/hb-subset-glyf.cc
gfx/harfbuzz/src/hb-subset-input.cc
gfx/harfbuzz/src/hb-subset-plan.cc
gfx/harfbuzz/src/hb-subset-plan.hh
gfx/harfbuzz/src/hb-subset-private.hh
gfx/harfbuzz/src/hb-subset.cc
gfx/harfbuzz/src/hb-subset.h
gfx/harfbuzz/src/hb-ucdn.cc
gfx/harfbuzz/src/hb-unicode-private.hh
gfx/harfbuzz/src/hb-unicode.cc
gfx/harfbuzz/src/hb-uniscribe.cc
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/src/hb.h
gfx/harfbuzz/src/main.cc
gfx/harfbuzz/src/moz.build
gfx/harfbuzz/src/sample.py
gfx/harfbuzz/src/test-buffer-serialize.cc
gfx/harfbuzz/src/test-size-params.cc
gfx/harfbuzz/src/test-would-substitute.cc
gfx/harfbuzz/src/test.cc
--- a/gfx/harfbuzz/Makefile.am
+++ b/gfx/harfbuzz/Makefile.am
@@ -4,17 +4,18 @@ NULL =
 
 ACLOCAL_AMFLAGS = -I m4
 
 SUBDIRS = src util test docs
 
 EXTRA_DIST = \
 	autogen.sh \
 	harfbuzz.doap \
-	README.python \
+	README.python.md \
+	README.wine.md \
 	BUILD.md \
 	RELEASING.md \
 	CMakeLists.txt \
 	replace-enum-strings.cmake \
 	$(NULL)
 
 MAINTAINERCLEANFILES = \
 	$(GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL) \
--- a/gfx/harfbuzz/NEWS
+++ b/gfx/harfbuzz/NEWS
@@ -1,8 +1,58 @@
+Overview of changes leading to 1.8.1
+Tuesday, June 12, 2018
+====================================
+- Fix hb-version.h file generation; last two releases went out with wrong ones.
+- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
+- Remove HB_SUBSET_BUILTIN build option.  Not necessary.
+
+Overview of changes leading to 1.8.0
+Tuesday, June 5, 2018
+====================================
+- Update to Unicode 11.0.0.
+
+
+Overview of changes leading to 1.7.7
+Tuesday, June 5, 2018
+====================================
+- Lots of internal changes, but not yet exposed externally.
+- All HarfBuzz objects are significantly smaller in size now.
+- Sinhala: Position repha on top of post-consonant, not base.
+  This better matches Windows 10 behavior, which was changed
+  from previous Windows versions.
+- New build options:
+  o New cpp macro HB_NO_ATEXIT
+  o New cpp macro HB_SUBSET_BUILTIN
+- Significant libharfbuzz-subset changes. API subject to change.
+- New API in libharfbuzz:
+
++hb_blob_create_from_file()
++hb_face_count()
+
+A hashmap implementation:
++hb-map.h
++HB_MAP_VALUE_INVALID
++hb_map_t
++hb_map_create()
++hb_map_get_empty()
++hb_map_reference()
++hb_map_destroy()
++hb_map_set_user_data()
++hb_map_get_user_data()
++hb_map_allocation_successful()
++hb_map_clear()
++hb_map_is_empty()
++hb_map_get_population()
++hb_map_set()
++hb_map_get()
++hb_map_del()
++hb_map_has()
+
+
 Overview of changes leading to 1.7.6
 Wednesday, March 7, 2018
 ====================================
 
 - Fix to hb_set_t binary operations. Ouch.
 - New experimental harfbuzz-subset library. All of hb-subset.h
   is experimental right now and API WILL change.
 
--- a/gfx/harfbuzz/README
+++ b/gfx/harfbuzz/README
@@ -1,12 +1,13 @@
 [![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
 [![Build status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
 [![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
 [![Coverity](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
 [![Coverage Status](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
 [ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
 
 This is HarfBuzz, a text shaping library.
 
 For bug reports, mailing list, and other information please visit:
 
   http://harfbuzz.org/
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,21 +1,15 @@
-gfx/harfbuzz status as of 2018-03-07:
+gfx/harfbuzz status as of 2018-06-12:
 
 This directory contains the HarfBuzz source from the 'master' branch of
 https://github.com/behdad/harfbuzz.
 
-Current version: 1.7.6
+Current version: 1.8.1
 
 UPDATING:
 
-Note that gfx/harfbuzz/src/hb-version.h is not present in the upstream Git
-repository. It is created at build time by the HarfBuzz build system;
-but as we don't use that build system in mozilla, it is necessary to refresh
-this file when updating HarfBuzz, and check it into the mozilla tree.
-
-The normal approach to updating HarfBuzz, therefore, is to pull the latest HB
-source into a scratch directory and do a local build; then copy the original
-sources AND the generated header mentioned above from the build directory into
-the mozilla tree.
+Our in-tree copy of HarfBuzz does not depend on any generated files from the
+upstream build system. Therefore, it should be sufficient to simply overwrite
+the in-tree files one the updated ones from upstream to perform updates.
 
 If the collection of source files changes, manual updates to moz.build may be
-needed, as we don't use the upstream makefiles.
+needed as we don't use the upstream makefiles.
--- a/gfx/harfbuzz/TODO
+++ b/gfx/harfbuzz/TODO
@@ -12,30 +12,26 @@ API issues:
 - Remove hb_ot_shape_glyphs_closure()?
 
 
 API additions
 =============
 
 - Language to/from script.
 
-- blob_from_file?
-
 - Add hb-cairo glue
 
 - Add sanitize API (and a cached version, that saves result on blob user-data)
 
 - BCP 47 language handling / API (language_matches?)
 
 - Add hb_font_create_unscaled()?
 
 - Add query / enumeration API for aalt-like features?
 
-- SFNT api? get_num_faces?
-
 - Add segmentation API
 
 - Add hb-fribidi glue?
 
 
 hb-view / hb-shape enhancements:
 ===============================
 
--- a/gfx/harfbuzz/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,11 +1,11 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.7.6],
+        [1.8.1],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
@@ -72,27 +72,41 @@ m4_ifdef([GTK_DOC_CHECK], [
 GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
 	if test "x$enable_gtk_doc" = xyes; then
 		have_gtk_doc=true
 	fi
 ], [
 	AM_CONDITIONAL([ENABLE_GTK_DOC], false)
 ])
 
-# Functions, and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l setlinebuf)
-AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h)
+# Functions and headers
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
+
+save_libs="$LIBS"
+LIBS="$LIBS -lm"
+AC_CHECK_FUNCS([round], ,[AC_CHECK_DECLS([round], , ,[#include <math.h>])])
+LIBS="$save_libs"
+
+AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
 
 # Compiler flags
 AC_CANONICAL_HOST
 AC_CHECK_ALIGNOF([struct{char;}])
 if test "x$GCC" = "xyes"; then
 
 	# Make symbols link locally
-	LDFLAGS="$LDFLAGS -Bsymbolic-functions"
+	AX_CHECK_LINK_FLAG([[-Bsymbolic-functions]], [LDFLAGS="$LDFLAGS -Bsymbolic-functions"])
+
+	# Make it possible to not link to libstdc++
+	# No threadsafe statics in C++ as we do it ourselves.
+	# We don't use these features, so it's safe to disable them
+	# even in the cases where we DO link to libstdc++.
+	# Put -fno-rtti before $CXXFLAGS such that users can re-enable it
+	# by overriding CXXFLAGS.
+	CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
 
 	# Assorted warnings
 	CXXFLAGS="$CXXFLAGS -Wcast-align"
 
 	case "$host" in
 		*-*-mingw*)
 		;;
 		*)
@@ -487,17 +501,16 @@ if test "$os_win32" = no && ! $have_pthr
 	AC_SEARCH_LIBS(sched_yield,rt,AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield]))
 fi
 
 dnl ===========================================================================
 
 AC_CONFIG_FILES([
 Makefile
 src/Makefile
-src/hb-version.h
 src/harfbuzz-config.cmake
 src/hb-ucdn/Makefile
 util/Makefile
 test/Makefile
 test/api/Makefile
 test/fuzzing/Makefile
 test/shaping/Makefile
 test/shaping/data/Makefile
@@ -527,16 +540,16 @@ Tools used for command-line utilities:
 	Cairo:			${have_cairo}
 	Fontconfig:		${have_fontconfig}
 
 Additional shapers (the more the merrier):
 	Graphite2:		${have_graphite2}
 
 Platform shapers (not normally needed):
 	CoreText:		${have_coretext}
+	DirectWrite:		${have_directwrite}
 	Uniscribe:		${have_uniscribe}
-	DirectWrite:		${have_directwrite}
 
 Other features:
 	Documentation:		${enable_gtk_doc}
 	GObject bindings:	${have_gobject}
 	Introspection:		${have_introspection}
 ])
--- a/gfx/harfbuzz/src/Makefile.am
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -7,44 +7,32 @@ BUILT_SOURCES =
 EXTRA_DIST =
 CLEANFILES =
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 TESTS =
 check_PROGRAMS =
 
-# The following warning options are useful for debugging: -Wpadded
-#AM_CXXFLAGS =
-
 # Convenience targets:
 lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la
-fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
+fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
 
 lib_LTLIBRARIES = libharfbuzz.la
 
 include Makefile.sources
 
 HBCFLAGS =
 HBLIBS =
 HBNONPCLIBS =
 HBDEPS =
 HBSOURCES =  $(HB_BASE_sources)
 HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
 HBHEADERS = $(HB_BASE_headers)
 
-if WITH_LIBSTDCXX
-HBNOLIBCXXCFLAGS =
-else
-# Make sure we don't link to libstdc++
-# No threadsafe statics in C++ as we do it ourselves
-HBCFLAGS += -fno-exceptions
-HBNOLIBCXXFLAGS = -fno-threadsafe-statics -fno-rtti
-endif
-
 if HAVE_OT
 HBSOURCES += $(HB_OT_sources)
 HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
 HBHEADERS += $(HB_OT_headers)
 endif
 
 if HAVE_FALLBACK
 HBSOURCES += $(HB_FALLBACK_sources)
@@ -112,16 +100,27 @@ HBLIBS   += hb-ucdn/libhb-ucdn.la
 HBSOURCES += $(HB_UCDN_sources)
 hb-ucdn/libhb-ucdn.la: ucdn
 ucdn:
 	@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
 endif
 DIST_SUBDIRS += hb-ucdn
 
 
+BUILT_SOURCES += \
+	hb-version.h
+
+$(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac
+	$(AM_V_GEN) $(SED) \
+		-e 's/[@]HB_VERSION_MAJOR@/$(HB_VERSION_MAJOR)/' \
+		-e 's/[@]HB_VERSION_MINOR@/$(HB_VERSION_MINOR)/' \
+		-e 's/[@]HB_VERSION_MICRO@/$(HB_VERSION_MICRO)/' \
+		-e 's/[@]HB_VERSION@/$(HB_VERSION)/' \
+		"$<" > "$@" || ($(RM) "$@"; false)
+
 # Put the library together
 
 HBLIBS += $(HBNONPCLIBS)
 
 if OS_WIN32
 export_symbols = -export-symbols harfbuzz.def
 harfbuzz_def_dependency = harfbuzz.def
 export_symbols_subset = -export-symbols harfbuzz-subset.def
@@ -142,34 +141,34 @@ else
 chosen_linker = $(CXXLINK)
 endif
 endif
 endif
 
 @CODE_COVERAGE_RULES@
 
 base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
-libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS) $(CODE_COVERAGE_LDFLAGS)
+libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS)
 libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
-libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(HBNOLIBCXXFLAGS) $(CODE_COVERAGE_CFLAGS)
-libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols)
+libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_la_LIBADD = $(HBLIBS)
 EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
 nodist_pkginclude_HEADERS =
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = harfbuzz.pc
 cmakedir = $(libdir)/cmake/harfbuzz
 cmake_DATA = harfbuzz-config.cmake
-EXTRA_DIST += harfbuzz.pc.in harfbuzz-config.cmake.in
+EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
 
 lib_LTLIBRARIES += libharfbuzz-subset.la
 libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
-libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS)
-libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset)
+libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_subset_la_LIBADD = libharfbuzz.la
 EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency)
 pkginclude_HEADERS += $(HB_SUBSET_headers)
 pkgconfig_DATA += harfbuzz-subset.pc
 EXTRA_DIST += harfbuzz-subset.pc.in
 
 FUZZING_CPPFLAGS = \
 	-DHB_NDEBUG \
@@ -179,67 +178,76 @@ FUZZING_CPPFLAGS = \
 	-DHB_SANITIZE_MAX_OPS_MIN=128 \
 	-DHB_BUFFER_MAX_LEN_FACTOR=3 \
 	-DHB_BUFFER_MAX_LEN_MIN=8 \
 	-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
 	-DHB_BUFFER_MAX_OPS_FACTOR=8 \
 	-DHB_BUFFER_MAX_OPS_MIN=64 \
 	-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
 	$(NULL)
-EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
+EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
+
 libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS)
 libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
 libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
 libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
 libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
 EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
 CLEANFILES += libharfbuzz-fuzzing.la
 
+libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS)
+libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES)
+libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
+libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
+libharfbuzz_subset_fuzzing_la_LIBADD = $(libharfbuzz_subset_la_LIBADD)
+EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES)
+CLEANFILES += libharfbuzz-subset-fuzzing.la
+
 if HAVE_ICU
 if HAVE_ICU_BUILTIN
 HBCFLAGS += $(ICU_CFLAGS)
 HBLIBS += $(ICU_LIBS)
 HBSOURCES += $(HB_ICU_sources)
 HBHEADERS += $(HB_ICU_headers)
 else
 lib_LTLIBRARIES += libharfbuzz-icu.la
 libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
-libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS)
-libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu)
+libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
 EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
 pkginclude_HEADERS += $(HB_ICU_headers)
 pkgconfig_DATA += harfbuzz-icu.pc
 endif
 endif
 EXTRA_DIST += harfbuzz-icu.pc.in
 
 if HAVE_GOBJECT
 lib_LTLIBRARIES += libharfbuzz-gobject.la
 libharfbuzz_gobject_la_LINK = $(chosen_linker) $(libharfbuzz_gobject_la_LDFLAGS)
 libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_DIST_sources)
 nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_NODIST_sources)
-libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(HBNOLIBCXXFLAGS) $(GOBJECT_CFLAGS)
-libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags)
+libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_CFLAGS)
+libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS)
 libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
 EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency)
 pkginclude_HEADERS += $(HB_GOBJECT_DIST_headers)
 nodist_pkginclude_HEADERS += $(HB_GOBJECT_NODIST_headers)
 pkgconfig_DATA += harfbuzz-gobject.pc
 
 BUILT_SOURCES += \
 	$(HB_GOBJECT_ENUM_sources) \
 	$(HB_GOBJECT_ENUM_headers) \
 	$(NULL)
 DISTCLEANFILES += \
 	$(HB_GOBJECT_ENUM_sources) \
 	$(HB_GOBJECT_ENUM_headers) \
 	$(NULL)
 hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
-	$(AM_V_GEN) $(GLIB_MKENUMS) \
+	$(AM_V_GEN) PYTHONIOENCODING=UTF-8 $(GLIB_MKENUMS) \
 		--identifier-prefix hb_ --symbol-prefix hb_gobject \
 		--template $^ | \
 	sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
 	|| ($(RM) "$@"; false)
 endif
 EXTRA_DIST += \
 	harfbuzz-gobject.pc.in \
 	hb-gobject-enums.cc.tmpl \
@@ -264,46 +272,46 @@ CLEANFILES += $(pkgconfig_DATA)
 
 DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def
 if HAVE_GOBJECT
 DEF_FILES += harfbuzz-gobject.def
 endif
 check: $(DEF_FILES) # For check-symbols.sh
 CLEANFILES += $(DEF_FILES)
 harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
-	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
+	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
 harfbuzz-subset.def: $(HB_SUBSET_headers)
-	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
+	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
 harfbuzz-icu.def: $(HB_ICU_headers)
-	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
+	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
 harfbuzz-gobject.def: $(HB_GOBJECT_headers)
-	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
+	$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py "$@"
 
 
 GENERATORS = \
 	gen-arabic-table.py \
 	gen-indic-table.py \
 	gen-use-table.py \
 	gen-def.py \
 	$(NULL)
 EXTRA_DIST += $(GENERATORS)
 
 unicode-tables: arabic-table indic-table use-table
 
 arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
-	|| ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
+	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
+	|| ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false)
 
-indic-table: gen-indic-table.py IndicSyllabicCategory-7.0.0.txt IndicMatraCategory-7.0.0.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
-	|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
+indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
+	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
+	|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
 
 use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
-	$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-use-table.cc \
-	|| ($(RM) hb-ot-shape-complex-use-table.cc; false)
+	$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
+	|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
 
 built-sources: $(BUILT_SOURCES)
 
 .PHONY: unicode-tables arabic-table indic-table use-table built-sources
 
 RAGEL_GENERATED = \
 	$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
 	$(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \
@@ -360,34 +368,47 @@ TESTS += $(dist_check_SCRIPTS)
 
 if !WITH_LIBSTDCXX
 dist_check_SCRIPTS += \
 	check-libstdc++.sh \
 	$(NULL)
 endif
 
 check_PROGRAMS += \
+	dump-fon \
 	dump-indic-data \
 	dump-khmer-data \
 	dump-myanmar-data \
 	dump-use-data \
 	$(NULL)
+dump_fon_SOURCES = dump-fon.cc
+dump_fon_CPPFLAGS = $(HBCFLAGS)
+dump_fon_LDADD = libharfbuzz.la $(HBLIBS)
 dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
 dump_indic_data_CPPFLAGS = $(HBCFLAGS)
 dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
 dump_khmer_data_SOURCES = dump-khmer-data.cc hb-ot-shape-complex-indic-table.cc
 dump_khmer_data_CPPFLAGS = $(HBCFLAGS)
 dump_khmer_data_LDADD = libharfbuzz.la $(HBLIBS)
 dump_myanmar_data_SOURCES = dump-myanmar-data.cc hb-ot-shape-complex-indic-table.cc
 dump_myanmar_data_CPPFLAGS = $(HBCFLAGS)
 dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS)
 dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
 dump_use_data_CPPFLAGS = $(HBCFLAGS)
 dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
 
+if HAVE_FREETYPE
+if HAVE_CAIRO_FT
+check_PROGRAMS += dump-emoji
+dump_emoji_SOURCES = dump-emoji.cc
+dump_emoji_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
+dump_emoji_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
+endif # HAVE_CAIRO_FT
+endif # HAVE_FREETYPE
+
 check_PROGRAMS += test-ot-tag test-unicode-ranges
 TESTS += test-ot-tag test-unicode-ranges
 
 test_ot_tag_SOURCES = hb-ot-tag.cc
 test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
 test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
 
 test_unicode_ranges_SOURCES = test-unicode-ranges.cc
--- a/gfx/harfbuzz/src/Makefile.sources
+++ b/gfx/harfbuzz/src/Makefile.sources
@@ -1,23 +1,26 @@
 # Base and default-included sources and headers
 
 HB_BASE_sources = \
 	hb-atomic-private.hh \
+	hb-blob-private.hh \
 	hb-blob.cc \
 	hb-buffer-private.hh \
 	hb-buffer-serialize.cc \
 	hb-buffer.cc \
 	hb-common.cc \
 	hb-debug.hh \
 	hb-dsalgs.hh \
 	hb-face-private.hh \
 	hb-face.cc \
 	hb-font-private.hh \
 	hb-font.cc \
+	hb-map-private.hh \
+	hb-map.cc \
 	hb-mutex-private.hh \
 	hb-object-private.hh \
 	hb-open-file-private.hh \
 	hb-open-type-private.hh \
 	hb-ot-color-cbdt-table.hh \
 	hb-ot-cmap-table.hh \
 	hb-ot-glyf-table.hh \
 	hb-ot-hdmx-table.hh \
@@ -38,16 +41,17 @@ HB_BASE_sources = \
 	hb-set.cc \
 	hb-shape.cc \
 	hb-shape-plan-private.hh \
 	hb-shape-plan.cc \
 	hb-shaper-list.hh \
 	hb-shaper-impl-private.hh \
 	hb-shaper-private.hh \
 	hb-shaper.cc \
+	hb-static.cc \
 	hb-string-array.hh \
 	hb-unicode-private.hh \
 	hb-unicode.cc \
 	hb-utf-private.hh \
 	hb-warning.cc \
 	$(NULL)
 
 HB_BASE_RAGEL_GENERATED_sources = \
@@ -62,48 +66,56 @@ HB_BASE_RAGEL_sources = \
 HB_BASE_headers = \
 	hb.h \
 	hb-blob.h \
 	hb-buffer.h \
 	hb-common.h \
 	hb-deprecated.h \
 	hb-face.h \
 	hb-font.h \
+	hb-map.h \
 	hb-set.h \
 	hb-shape.h \
 	hb-shape-plan.h \
 	hb-unicode.h \
 	hb-version.h \
 	$(NULL)
 
 HB_FALLBACK_sources = \
 	hb-fallback-shape.cc	\
 	$(NULL)
 
 HB_OT_sources = \
 	hb-aat-layout.cc \
 	hb-aat-layout-common-private.hh \
 	hb-aat-layout-ankr-table.hh \
+	hb-aat-layout-bsln-table.hh \
+	hb-aat-layout-feat-table.hh \
 	hb-aat-layout-kerx-table.hh \
 	hb-aat-layout-morx-table.hh \
 	hb-aat-layout-trak-table.hh \
 	hb-aat-layout-private.hh \
+	hb-aat-fmtx-table.hh \
+	hb-aat-gcid-table.hh \
+	hb-aat-ltag-table.hh \
 	hb-ot-font.cc \
 	hb-ot-layout.cc \
 	hb-ot-layout-base-table.hh \
 	hb-ot-layout-common-private.hh \
 	hb-ot-layout-gdef-table.hh \
 	hb-ot-layout-gpos-table.hh \
 	hb-ot-layout-gsubgpos-private.hh \
 	hb-ot-layout-gsub-table.hh \
 	hb-ot-layout-jstf-table.hh \
 	hb-ot-layout-private.hh \
 	hb-ot-color.cc \
 	hb-ot-color-colr-table.hh \
 	hb-ot-color-cpal-table.hh \
+	hb-ot-color-sbix-table.hh \
+	hb-ot-color-svg-table.hh \
 	hb-ot-map.cc \
 	hb-ot-map-private.hh \
 	hb-ot-math.cc \
 	hb-ot-math-table.hh \
 	hb-ot-shape.cc \
 	hb-ot-shape-complex-arabic.cc \
 	hb-ot-shape-complex-arabic-fallback.hh \
 	hb-ot-shape-complex-arabic-private.hh \
@@ -186,16 +198,17 @@ HB_UNISCRIBE_headers = hb-uniscribe.h
 HB_UCDN_sources  = hb-ucdn.cc
 
 # Sources for libharfbuzz-gobject and libharfbuzz-icu
 HB_ICU_sources = hb-icu.cc
 HB_ICU_headers = hb-icu.h
 
 # Sources for libharfbuzz-subset
 HB_SUBSET_sources = \
+	hb-static.cc \
 	hb-subset.cc \
 	hb-subset-glyf.cc \
 	hb-subset-input.cc \
 	hb-subset-plan.cc \
 	$(NULL)
 
 HB_SUBSET_headers = \
 	hb-subset.h \
--- a/gfx/harfbuzz/src/check-symbols.sh
+++ b/gfx/harfbuzz/src/check-symbols.sh
@@ -25,28 +25,26 @@ for soname in harfbuzz harfbuzz-subset h
 		# On macOS, C symbols are prefixed with _
 		symprefix=
 		if test $suffix = dylib; then symprefix=_; fi
 
 		EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
 
 		prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
 
-		echo
 		echo "Checking that $so does not expose internal symbols"
 		if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}\(_\|$\)"; then
 			echo "Ouch, internal symbols exposed"
 			stat=1
 		fi
 
 		def=$soname.def
 		if ! test -f "$def"; then
 			echo "'$def' not found; skipping"
 		else
-			echo
 			echo "Checking that $so has the same symbol list as $def"
 			{
 				echo EXPORTS
 				echo "$EXPORTED_SYMBOLS" | sed -e "s/^${symprefix}hb/hb/g"
 				# cheat: copy the last line from the def file!
 				tail -n1 "$def"
 			} | c++filt | diff "$def" - >&2 || stat=1
 		fi
--- a/gfx/harfbuzz/src/dev-run.sh
+++ b/gfx/harfbuzz/src/dev-run.sh
@@ -1,13 +1,14 @@
 #!/bin/bash
 # Suggested setup to use the script:
 #  (on the root of the project)
-#  $ NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
-#  $ mkdir build && cd build && ../configure && make -j5 && cd ..
+#  $ NOCONFIGURE=1 ./autogen.sh && mkdir build && cd build
+#  $ ../configure --with-freetype --with-glib --with-gobject --with-cairo
+#  $ make -j5 && cd ..
 #  $ src/dev-run.sh [FONT-FILE] [TEXT]
 #
 # Or, using cmake:
 #  $ cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild
 #  $ src/dev-run.sh [FONT-FILE] [TEXT]
 #
 # If you want to open the result rendering using a GUI app,
 #  $ src/dev-run.sh open [FONT-FILE] [TEXT]
@@ -38,17 +39,17 @@ st="\a"
 if [[ $TERM == screen* ]]; then st="\a"; fi
 
 
 tmp=tmp.png
 [ -f 'build/build.ninja' ] && CMAKENINJA=TRUE
 # or "fswatch -0 . -e build/ -e .git"
 find src/ | entr printf '\0' | while read -d ""; do
 	clear
-	echo '===================================================='
+	yes = | head -n`tput cols` | tr -d '\n'
 	if [[ $CMAKENINJA ]]; then
 		ninja -Cbuild hb-shape hb-view && {
 			build/hb-shape $@
 			if [ $openimg ]; then
 				build/hb-view $@ -O png -o $tmp
 				$OPEN $tmp
 			elif [ $img ]; then
 				build/hb-view $@ -O png -o $tmp
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/dump-emoji.cc
@@ -0,0 +1,263 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-static.cc"
+#include "hb-ot-color-cbdt-table.hh"
+#include "hb-ot-color-colr-table.hh"
+#include "hb-ot-color-cpal-table.hh"
+#include "hb-ot-color-sbix-table.hh"
+#include "hb-ot-color-svg-table.hh"
+
+#include "hb-ft.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#include <cairo.h>
+#include <cairo-ft.h>
+#include <cairo-svg.h>
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+void cbdt_callback (const uint8_t* data, unsigned int length,
+                    unsigned int group, unsigned int gid)
+{
+  char output_path[255];
+  sprintf (output_path, "out/cbdt-%d-%d.png", group, gid);
+  FILE *f = fopen (output_path, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+void sbix_callback (const uint8_t* data, unsigned int length,
+                    unsigned int group, unsigned int gid)
+{
+  char output_path[255];
+  sprintf (output_path, "out/sbix-%d-%d.png", group, gid);
+  FILE *f = fopen (output_path, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+void svg_callback (const uint8_t* data, unsigned int length,
+                   unsigned int start_glyph, unsigned int end_glyph)
+{
+  char output_path[255];
+  if (start_glyph == end_glyph)
+    sprintf (output_path, "out/svg-%d.svg", start_glyph);
+  else
+    sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph);
+
+  // append "z" if the content is gzipped
+  if ((data[0] == 0x1F) && (data[1] == 0x8B))
+    strcat (output_path, "z");
+
+  FILE *f = fopen (output_path, "wb");
+  fwrite (data, 1, length, f);
+  fclose (f);
+}
+
+void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs,
+			  const OT::COLR *colr, const OT::CPAL *cpal)
+{
+  for (unsigned int i = 0; i < num_glyphs; ++i)
+  {
+    unsigned int first_layer_index, num_layers;
+    if (colr->get_base_glyph_record (i, &first_layer_index, &num_layers))
+    {
+      // Measure
+      cairo_text_extents_t extents;
+      {
+	cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+	cairo_t *cr = cairo_create (surface);
+	cairo_set_font_face (cr, cairo_face);
+	cairo_set_font_size (cr, upem);
+
+	cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t));
+	for (unsigned int j = 0; j < num_layers; ++j)
+	{
+	  hb_codepoint_t glyph_id;
+	  unsigned int color_index;
+	  colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
+	  glyphs[j].index = glyph_id;
+	}
+	cairo_glyph_extents (cr, glyphs, num_layers, &extents);
+	free (glyphs);
+	cairo_surface_destroy (surface);
+	cairo_destroy (cr);
+      }
+
+      // Add a slight margin
+      extents.width += extents.width / 10;
+      extents.height += extents.height / 10;
+      extents.x_bearing -= extents.width / 20;
+      extents.y_bearing -= extents.height / 20;
+
+      // Render
+      unsigned int pallet_count = cpal->get_palette_count ();
+      for (unsigned int pallet = 0; pallet < pallet_count; ++pallet) {
+	char output_path[255];
+
+	// If we have more than one pallet, use a better namin
+	if (pallet_count == 1)
+	  sprintf (output_path, "out/colr-%d.svg", i);
+	else
+	  sprintf (output_path, "out/colr-%d-%d.svg", i, pallet);
+
+	cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
+	cairo_t *cr = cairo_create (surface);
+	cairo_set_font_face (cr, cairo_face);
+	cairo_set_font_size (cr, upem);
+
+	for (unsigned int j = 0; j < num_layers; ++j)
+	{
+	  hb_codepoint_t glyph_id;
+	  unsigned int color_index;
+	  colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
+
+	  uint32_t color = cpal->get_color_record_argb (color_index, pallet);
+	  int alpha = color & 0xFF;
+	  int r = (color >> 8) & 0xFF;
+	  int g = (color >> 16) & 0xFF;
+	  int b = (color >> 24) & 0xFF;
+	  cairo_set_source_rgba (cr, r / 255.f, g / 255.f, b / 255.f, alpha);
+
+	  cairo_glyph_t glyph;
+	  glyph.index = glyph_id;
+	  glyph.x = -extents.x_bearing;
+	  glyph.y = -extents.y_bearing;
+	  cairo_show_glyphs (cr, &glyph, 1);
+	}
+
+	cairo_surface_destroy (surface);
+	cairo_destroy (cr);
+      }
+    }
+  }
+}
+
+void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs)
+{
+  // Dump every glyph available on the font
+  return; // disabled for now
+  for (unsigned int i = 0; i < num_glyphs; ++i)
+  {
+    cairo_text_extents_t extents;
+    cairo_glyph_t glyph = {0};
+    glyph.index = i;
+
+    // Measure
+    {
+      cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+      cairo_t *cr = cairo_create (surface);
+      cairo_set_font_face (cr, cairo_face);
+      cairo_set_font_size (cr, upem);
+
+      cairo_glyph_extents (cr, &glyph, 1, &extents);
+      cairo_surface_destroy (surface);
+      cairo_destroy (cr);
+    }
+
+    // Add a slight margin
+    extents.width += extents.width / 10;
+    extents.height += extents.height / 10;
+    extents.x_bearing -= extents.width / 20;
+    extents.y_bearing -= extents.height / 20;
+
+    // Render
+    {
+      char output_path[255];
+      sprintf (output_path, "out/%d.svg", i);
+      cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
+      cairo_t *cr = cairo_create (surface);
+      cairo_set_font_face (cr, cairo_face);
+      cairo_set_font_size (cr, upem);
+      glyph.x = -extents.x_bearing;
+      glyph.y = -extents.y_bearing;
+      cairo_show_glyphs (cr, &glyph, 1);
+      cairo_surface_destroy (surface);
+      cairo_destroy (cr);
+    }
+  }
+}
+
+int main (int argc, char **argv)
+{
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+  hb_face_t *face = hb_face_create (blob, 0);
+  hb_font_t *font = hb_font_create (face);
+
+  OT::CBDT::accelerator_t cbdt;
+  cbdt.init (face);
+  cbdt.dump (cbdt_callback);
+  cbdt.fini ();
+
+  OT::sbix::accelerator_t sbix;
+  sbix.init (face);
+  sbix.dump (sbix_callback);
+  sbix.fini ();
+
+  OT::SVG::accelerator_t svg;
+  svg.init (face);
+  svg.dump (svg_callback);
+  svg.fini ();
+
+  OT::Sanitizer<OT::COLR> sanitizerCOLR;
+  hb_blob_t* colr_blob = sanitizerCOLR.sanitize (face->reference_table (HB_OT_TAG_COLR));
+  const OT::COLR *colr = colr_blob->as<OT::COLR> ();
+
+  OT::Sanitizer<OT::CPAL> sanitizerCPAL;
+  hb_blob_t* cpal_blob = sanitizerCPAL.sanitize (face->reference_table (HB_OT_TAG_CPAL));
+  const OT::CPAL *cpal = cpal_blob->as<OT::CPAL> ();
+
+  cairo_font_face_t *cairo_face;
+  {
+    FT_Library library;
+    FT_Init_FreeType (&library);
+    FT_Face ftface;
+    FT_New_Face (library, argv[1], 0, &ftface);
+    cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0);
+  }
+  unsigned int num_glyphs = hb_face_get_glyph_count (face);
+  unsigned int upem = hb_face_get_upem (face);
+  colr_cpal_rendering (cairo_face, upem, num_glyphs, colr, cpal);
+  dump_glyphs (cairo_face, upem, num_glyphs);
+
+
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+  hb_blob_destroy (blob);
+
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/dump-fon.cc
@@ -0,0 +1,555 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-static.cc"
+#include <stdio.h>
+#include <stdlib.h>
+#include "hb-open-type-private.hh"
+
+template <typename Type, int Bytes> struct LEInt;
+
+template <typename Type>
+struct LEInt<Type, 1>
+{
+  public:
+  inline void set (Type V)
+  {
+    v = V;
+  }
+  inline operator Type (void) const
+  {
+    return v;
+  }
+  private: uint8_t v;
+};
+template <typename Type>
+struct LEInt<Type, 2>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[1] = (V >>  8) & 0xFF;
+    v[0] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[1] <<  8)
+         + (v[0]      );
+  }
+  private: uint8_t v[2];
+};
+template <typename Type>
+struct LEInt<Type, 3>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[2] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[0] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[2] << 16)
+         + (v[1] <<  8)
+         + (v[0]      );
+  }
+  private: uint8_t v[3];
+};
+template <typename Type>
+struct LEInt<Type, 4>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[3] = (V >> 24) & 0xFF;
+    v[2] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[0] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[3] << 24)
+         + (v[2] << 16)
+         + (v[1] <<  8)
+         + (v[0]      );
+  }
+  private: uint8_t v[4];
+};
+
+template <typename Type, unsigned int Size>
+struct LEIntType
+{
+  inline void set (Type i) { v.set (i); }
+  inline operator Type(void) const { return v; }
+  inline bool sanitize (OT::hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+  protected:
+  LEInt<Type, Size> v;
+  public:
+  DEFINE_SIZE_STATIC (Size);
+};
+
+typedef LEIntType<uint8_t,  1> LEUINT8;		/* 8-bit unsigned integer. */
+typedef LEIntType<int8_t,   1> LEINT8;		/* 8-bit signed integer. */
+typedef LEIntType<uint16_t, 2> LEUINT16;	/* 16-bit unsigned integer. */
+typedef LEIntType<int16_t,  2> LEINT16;		/* 16-bit signed integer. */
+typedef LEIntType<uint32_t, 4> LEUINT32;	/* 32-bit unsigned integer. */
+typedef LEIntType<int32_t,  4> LEINT32;		/* 32-bit signed integer. */
+typedef LEIntType<uint32_t, 3> LEUINT24;	/* 24-bit unsigned integer. */
+
+
+struct LE_FONTINFO16
+{
+  inline bool sanitize (OT::hb_sanitize_context_t *c, unsigned int length) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && c->check_range (this, length)));
+  }
+
+  // https://msdn.microsoft.com/en-us/library/cc194829.aspx
+  enum charset_t
+  {
+    // dfCharSet possible values and the codepage they are indicating to
+    ANSI	= 0x00,	// 1252
+    DEFAULT	= 0x01,	//
+    SYMBOL	= 0x02,	//
+    SHIFTJIS	= 0x80,	// 932
+    HANGUL	= 0x81,	// 949
+    GB2312	= 0x86,	// 936
+    CHINESEBIG5	= 0x88,	// 950
+    GREEK	= 0xA1,	// 1253
+    TURKISH	= 0xA2,	// 1254
+    HEBREW	= 0xB1,	// 1255
+    ARABIC	= 0xB2,	// 1256
+    BALTIC	= 0xBA,	// 1257
+    RUSSIAN	= 0xCC,	// 1251
+    THAI	= 0xDE,	// 874
+    EE		= 0xEE,	// 1250
+    OEM		= 0xFF	//
+  };
+
+  inline const char* get_charset() const
+  {
+    switch (dfCharSet) {
+    case ANSI: return "ISO8859";
+    case DEFAULT: return "WinDefault";
+    case SYMBOL: return "Symbol";
+    case SHIFTJIS: return "JISX0208.1983";
+    case HANGUL: return "MSHangul";
+    case GB2312: return "GB2312.1980";
+    case CHINESEBIG5: return "Big5";
+    case GREEK: return "CP1253";
+    case TURKISH: return "CP1254";
+    case HEBREW: return "CP1255";
+    case ARABIC: return "CP1256";
+    case BALTIC: return "CP1257";
+    case RUSSIAN: return "CP1251";
+    case THAI: return "CP874";
+    case EE: return "CP1250";
+    case OEM: return "OEM";
+    default: return "Unknown";
+    }
+  }
+
+  inline unsigned int get_version () const
+  {
+    return dfVersion;
+  }
+
+  inline unsigned int get_weight () const
+  {
+    return dfWeight;
+  }
+
+  enum weight_t {
+    DONTCARE	= 0,
+    THIN	= 100,
+    EXTRALIGHT	= 200,
+    ULTRALIGHT	= 200,
+    LIGHT	= 300,
+    NORMAL	= 400,
+    REGULAR	= 400,
+    MEDIUM	= 500,
+    SEMIBOLD	= 600,
+    DEMIBOLD	= 600,
+    BOLD	= 700,
+    EXTRABOLD	= 800,
+    ULTRABOLD	= 800,
+    HEAVY	= 900,
+    BLACK	= 900
+  };
+
+  inline void dump () const
+  {
+    // With https://github.com/juanitogan/mkwinfont/blob/master/python/dewinfont.py help
+    // Should be implemented differently eventually, but for now
+    unsigned int ctstart;
+    unsigned int ctsize;
+    if (dfVersion == 0x200)
+    {
+      ctstart = 0x76;
+      ctsize = 4;
+    }
+    else
+    {
+      return; // must of ".fon"s are version 2 and even dewinfont V1 implmentation doesn't seem correct
+      ctstart = 0x94;
+      ctsize = 6;
+    }
+    // unsigned int maxwidth = 0;
+    for (unsigned int i = dfFirstChar; i < dfLastChar; ++i)
+    {
+      unsigned int entry = ctstart + ctsize * (i-dfFirstChar);
+      unsigned int w = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry);
+
+      unsigned int off;
+      if (ctsize == 4)
+        off = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry+2);
+      else
+        off = (uint32_t) OT::StructAtOffset<LEUINT32> (this, entry+2);
+
+      unsigned int widthbytes = (w + 7) / 8;
+      for (unsigned int j = 0; j < dfPixHeight; ++j)
+      {
+        for (unsigned int k = 0; k < widthbytes; ++k)
+	{
+	  unsigned int bytepos = off + k * dfPixHeight + j;
+	  const uint8_t b = (uint8_t) OT::StructAtOffset<LEINT8> (this, bytepos);
+	  for (unsigned int a = 128; a > 0; a >>= 1)
+	    printf (b & a ? "x" : ".");
+	}
+	printf ("\n");
+      }
+      printf ("\n\n");
+    }
+  }
+
+  protected:
+  LEUINT16	dfVersion;
+  LEUINT32	dfSize;
+  LEUINT8	dfCopyright[60];
+  LEUINT16	dfType;
+  LEUINT16	dfPoints;
+  LEUINT16	dfVertRes;
+  LEUINT16	dfHorizRes;
+  LEUINT16	dfAscent;
+  LEUINT16	dfInternalLeading;
+  LEUINT16	dfExternalLeading;
+  LEUINT8	dfItalic;
+  LEUINT8	dfUnderline;
+  LEUINT8	dfStrikeOut;
+  LEUINT16	dfWeight; // see weight_t
+  LEUINT8	dfCharSet;  // see charset_t
+  LEUINT16	dfPixWidth;
+  LEUINT16	dfPixHeight;
+  LEUINT8	dfPitchAndFamily;
+  LEUINT16	dfAvgWidth;
+  LEUINT16	dfMaxWidth;
+  LEUINT8	dfFirstChar;
+  LEUINT8	dfLastChar;
+  LEUINT8	dfDefaultChar;
+  LEUINT8	dfBreakChar;
+  LEUINT16	dfWidthBytes;
+  LEUINT32	dfDevice;
+  LEUINT32	dfFace;
+  LEUINT32	dfBitsPointer;
+  LEUINT32	dfBitsOffset;
+  LEUINT8	dfReserved;
+//   LEUINT32	dfFlags;
+//   LEUINT16	dfAspace;
+//   LEUINT16	dfBspace;
+//   LEUINT16	dfCspace;
+//   LEUINT32	dfColorPointer;
+//   LEUINT32	dfReserved1[4];
+  OT::UnsizedArrayOf<LEUINT8>
+		dataZ;
+  public:
+  DEFINE_SIZE_ARRAY (118, dataZ);
+};
+
+struct NE_NAMEINFO
+{
+  friend struct NE_TYPEINFO;
+
+  inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  get_font (base, shift).sanitize (c, length << shift)));
+  }
+
+  inline const LE_FONTINFO16& get_font (const void *base, int shift) const
+  {
+    return OT::StructAtOffset<LE_FONTINFO16> (base, offset << shift);
+  }
+
+  enum resource_type_flag_t {
+    NONE     = 0x0000,
+    MOVEABLE = 0x0010,
+    PURE     = 0x0020,
+    PRELOAD  = 0x0040
+  };
+
+  protected:
+  LEUINT16	offset;	// Should be shifted with alignmentShiftCount before use
+  LEUINT16	length;	// Should be shifted with alignmentShiftCount before use
+  LEUINT16	flags;	// resource_type_flag_t
+  LEUINT16	id;
+  LEUINT16	handle;
+  LEUINT16	usage;
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct NE_TYPEINFO
+{
+  inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && resources.sanitize (c, count, base, shift));
+  }
+
+  inline unsigned int get_size (void) const
+  { return 8 + count * NE_NAMEINFO::static_size; }
+
+  inline const NE_TYPEINFO& next () const
+  {
+    const NE_TYPEINFO& next = OT::StructAfter<NE_TYPEINFO> (*this);
+    if (type_id == 0)
+      return Null(NE_TYPEINFO);
+    return next;
+  }
+
+  inline const LE_FONTINFO16& get_font (unsigned int idx, const void *base, int shift) const
+  {
+    if (idx < count)
+      return resources[idx].get_font (base, shift);
+    return Null(LE_FONTINFO16);
+  }
+
+  inline unsigned int get_count () const
+  {
+    return count;
+  }
+
+  inline unsigned int get_type_id () const
+  {
+    return type_id;
+  }
+
+  enum type_id_t {
+    CURSOR		= 0x8001,
+    BITMAP		= 0x8002,
+    ICON		= 0x8003,
+    MENU		= 0x8004,
+    DIALOG		= 0x8005,
+    STRING		= 0x8006,
+    FONT_DIRECTORY	= 0x8007,
+    FONT		= 0x8008,
+    ACCELERATOR_TABLE	= 0x8009,
+    RESOURCE_DATA	= 0x800a,
+    GROUP_CURSOR	= 0x800c,
+    GROUP_ICON		= 0x800e,
+    VERSION		= 0x8010
+  };
+
+  protected:
+  LEUINT16	type_id; // see type_id_t
+  LEUINT16	count;
+  LEUINT32	resloader;
+  OT::UnsizedArrayOf<NE_NAMEINFO>
+		resources;
+  public:
+  DEFINE_SIZE_ARRAY (8, resources);
+};
+
+struct NE_RESOURCE_TABLE
+{
+  inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+
+    if (!c->check_struct (this))
+      return_trace (false);
+
+    const NE_TYPEINFO* n = &chain;
+    while (n != &Null(NE_TYPEINFO) && c->check_struct (n) && n->get_type_id () != 0)
+    {
+      if (n->get_type_id () == NE_TYPEINFO::FONT)
+	return_trace (n->sanitize (c, base, alignmentShiftCount));
+      n = &n->next();
+    }
+    return_trace (false);
+  }
+
+  inline unsigned int get_shift_value () const
+  {
+    return alignmentShiftCount;
+  }
+
+  inline const NE_TYPEINFO& get_fonts_entry () const
+  {
+    const NE_TYPEINFO* n = &chain;
+    while (n != &Null(NE_TYPEINFO) && n->get_type_id () != 0)
+    {
+      if (n->get_type_id () == NE_TYPEINFO::FONT)
+	return *n;
+      n = &n->next();
+    }
+    return Null(NE_TYPEINFO);
+  }
+
+  protected:
+  LEUINT16	alignmentShiftCount;
+  NE_TYPEINFO	chain;
+  // It is followed by an array of OT::ArrayOf<LEUINT8, LEUINT8> chars;
+  public:
+  DEFINE_SIZE_MIN (2);
+};
+
+// https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L2467
+struct LE_IMAGE_OS2_HEADER
+{
+  inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && (this+rsrctab).sanitize (c, base)));
+  }
+
+  inline const NE_RESOURCE_TABLE& get_resource_table () const
+  {
+    if (magic != 0x454E) // Only NE containers are support for now, NE == 0x454E
+      return Null(NE_RESOURCE_TABLE);
+    return this+rsrctab;
+  }
+
+  protected:
+  LEUINT16	magic;		/* 00 NE signature 'NE' */
+  LEUINT8	ver;		/* 02 Linker version number */
+  LEUINT8	rev;		/* 03 Linker revision number */
+  LEUINT16	enttab;		/* 04 Offset to entry table relative to NE */
+  LEUINT16	cbenttab;	/* 06 Length of entry table in bytes */
+  LEUINT32	crc;		/* 08 Checksum */
+  LEUINT16	flags;		/* 0c Flags about segments in this file */
+  LEUINT16	autodata;	/* 0e Automatic data segment number */
+  LEUINT16	heap;		/* 10 Initial size of local heap */
+  LEUINT16	stack;		/* 12 Initial size of stack */
+  LEUINT32	csip;		/* 14 Initial CS:IP */
+  LEUINT32	sssp;		/* 18 Initial SS:SP */
+  LEUINT16	cseg;		/* 1c # of entries in segment table */
+  LEUINT16	cmod;		/* 1e # of entries in module reference tab. */
+  LEUINT16	cbnrestab;	/* 20 Length of nonresident-name table     */
+  LEUINT16	segtab;		/* 22 Offset to segment table */
+  OT::OffsetTo<NE_RESOURCE_TABLE, LEUINT16>
+		rsrctab;	/* 24 Offset to resource table */
+  LEUINT16	restab;		/* 26 Offset to resident-name table */
+  LEUINT16	modtab;		/* 28 Offset to module reference table */
+  LEUINT16	imptab;		/* 2a Offset to imported name table */
+  LEUINT32	nrestab;	/* 2c Offset to nonresident-name table */
+  LEUINT16	cmovent;	/* 30 # of movable entry points */
+  LEUINT16	align;		/* 32 Logical sector alignment shift count */
+  LEUINT16	cres;		/* 34 # of resource segments */
+  LEUINT8	exetyp;		/* 36 Flags indicating target OS */
+  LEUINT8	flagsothers;	/* 37 Additional information flags */
+  LEUINT16	pretthunks;	/* 38 Offset to return thunks */
+  LEUINT16	psegrefbytes;	/* 3a Offset to segment ref. bytes */
+  LEUINT16	swaparea;	/* 3c Reserved by Microsoft */
+  LEUINT16	expver;		/* 3e Expected Windows version number */
+  public:
+  DEFINE_SIZE_STATIC (64);
+};
+
+struct LE_IMAGE_DOS_HEADER {
+  inline bool sanitize (OT::hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  get_os2_header ().sanitize (c, this)));
+  }
+
+  inline const LE_IMAGE_OS2_HEADER& get_os2_header () const
+  {
+    return this+e_lfanew;
+  }
+
+  protected:
+  LEUINT16	e_magic;	// Magic number
+  LEUINT16	e_cblp;		// Bytes on last page of file
+  LEUINT16	e_cp;		// Pages in file
+  LEUINT16	e_crlc;		// Relocations
+  LEUINT16	e_cparhdr;	// Size of header in paragraphs
+  LEUINT16	e_minalloc;	// Minimum extra paragraphs needed
+  LEUINT16	e_maxalloc;	// Maximum extra paragraphs needed
+  LEUINT16	e_ss;		// Initial (relative) SS value
+  LEUINT16	e_sp;		// Initial SP value
+  LEUINT16	e_csum;		// Checksum
+  LEUINT16	e_ip;		// Initial IP value
+  LEUINT16	e_cs;		// Initial (relative) CS value
+  LEUINT16	e_lfarlc;	// File address of relocation table
+  LEUINT16	e_ovno;		// Overlay number
+  LEUINT16	e_res_0;	// Reserved words
+  LEUINT16	e_res_1;	// Reserved words
+  LEUINT16	e_res_2;	// Reserved words
+  LEUINT16	e_res_3;	// Reserved words
+  LEUINT16	e_oemid;	// OEM identifier (for e_oeminfo)
+  LEUINT16	e_oeminfo;	// OEM information; e_oemid specific
+  LEUINT16	e_res2_0;	// Reserved words
+  LEUINT16	e_res2_1;	// Reserved words
+  LEUINT16	e_res2_2;	// Reserved words
+  LEUINT16	e_res2_3;	// Reserved words
+  LEUINT16	e_res2_4;	// Reserved words
+  LEUINT16	e_res2_5;	// Reserved words
+  LEUINT16	e_res2_6;	// Reserved words
+  LEUINT16	e_res2_7;	// Reserved words
+  LEUINT16	e_res2_8;	// Reserved words
+  LEUINT16	e_res2_9;	// Reserved words
+  OT::OffsetTo<LE_IMAGE_OS2_HEADER, LEUINT32>
+		e_lfanew;	// File address of new exe header
+  public:
+  DEFINE_SIZE_STATIC (64);
+};
+
+int main (int argc, char** argv) {
+  hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+
+  OT::Sanitizer<LE_IMAGE_DOS_HEADER> sanitizer;
+  hb_blob_t *font_blob = sanitizer.sanitize (blob);
+  const LE_IMAGE_DOS_HEADER* dos_header = font_blob->as<LE_IMAGE_DOS_HEADER> ();
+
+  const NE_RESOURCE_TABLE &rtable = dos_header->get_os2_header ().get_resource_table ();
+  int shift = rtable.get_shift_value ();
+  const NE_TYPEINFO& entry = rtable.get_fonts_entry ();
+  for (unsigned int i = 0; i < entry.get_count (); ++i)
+  {
+    const LE_FONTINFO16& font = entry.get_font (i, dos_header, shift);
+    printf ("version: %x, weight: %d, charset: %s\n", font.get_version (),
+	    font.get_weight (), font.get_charset ());
+    // font.dump ();
+  }
+  return 0;
+}
--- a/gfx/harfbuzz/src/gen-arabic-table.py
+++ b/gfx/harfbuzz/src/gen-arabic-table.py
@@ -1,18 +1,19 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
-import sys
-import os.path
+from __future__ import print_function, division, absolute_import
+
+import io, os.path, sys
 
 if len (sys.argv) != 4:
-	print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
+	print ("usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
 	sys.exit (1)
 
-files = [file (x) for x in sys.argv[1:]]
+files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
 
 headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
 headers.append (["UnicodeData.txt does not have a header."])
 while files[0].readline ().find ('##################') < 0:
 	pass
 
 blocks = {}
 def read_blocks(f):
@@ -60,97 +61,97 @@ def print_joining_table(f):
 		values[u] = value
 
 	short_value = {}
 	for value in set([v for v in values.values()] + ['JOINING_TYPE_X']):
 		short = ''.join(x[0] for x in value.split('_')[2:])
 		assert short not in short_value.values()
 		short_value[value] = short
 
-	print
+	print ()
 	for value,short in short_value.items():
-		print "#define %s	%s" % (short, value)
+		print ("#define %s	%s" % (short, value))
 
 	uu = sorted(values.keys())
 	num = len(values)
 	all_blocks = set([blocks[u] for u in uu])
 
 	last = -100000
 	ranges = []
 	for u in uu:
 		if u - last <= 1+16*5:
 			ranges[-1][-1] = u
 		else:
 			ranges.append([u,u])
 		last = u
 
-	print
-	print "static const uint8_t joining_table[] ="
-	print "{"
+	print ()
+	print ("static const uint8_t joining_table[] =")
+	print ("{")
 	last_block = None
 	offset = 0
 	for start,end in ranges:
 
-		print
-		print "#define joining_offset_0x%04xu %d" % (start, offset)
+		print ()
+		print ("#define joining_offset_0x%04xu %d" % (start, offset))
 
 		for u in range(start, end+1):
 
 			block = blocks.get(u, last_block)
 			value = values.get(u, "JOINING_TYPE_X")
 
 			if block != last_block or u == start:
 				if u != start:
-					print
+					print ()
 				if block in all_blocks:
-					print "\n  /* %s */" % block
+					print ("\n  /* %s */" % block)
 				else:
-					print "\n  /* FILLER */"
+					print ("\n  /* FILLER */")
 				last_block = block
 				if u % 32 != 0:
-					print
-					print "  /* %04X */" % (u//32*32), "  " * (u % 32),
+					print ()
+					print ("  /* %04X */" % (u//32*32), "  " * (u % 32), end="")
 
 			if u % 32 == 0:
-				print
-				print "  /* %04X */ " % u,
-			sys.stdout.write("%s," % short_value[value])
-		print
+				print ()
+				print ("  /* %04X */ " % u, end="")
+			print ("%s," % short_value[value], end="")
+		print ()
 
 		offset += end - start + 1
-	print
+	print ()
 	occupancy = num * 100. / offset
-	print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
-	print
+	print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
+	print ()
 
 	page_bits = 12;
-	print
-	print "static unsigned int"
-	print "joining_type (hb_codepoint_t u)"
-	print "{"
-	print "  switch (u >> %d)" % page_bits
-	print "  {"
+	print ()
+	print ("static unsigned int")
+	print ("joining_type (hb_codepoint_t u)")
+	print ("{")
+	print ("  switch (u >> %d)" % page_bits)
+	print ("  {")
 	pages = set([u>>page_bits for u in [s for s,e in ranges]+[e for s,e in ranges]])
 	for p in sorted(pages):
-		print "    case 0x%0Xu:" % p
+		print ("    case 0x%0Xu:" % p)
 		for (start,end) in ranges:
 			if p not in [start>>page_bits, end>>page_bits]: continue
 			offset = "joining_offset_0x%04xu" % start
-			print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
-		print "      break;"
-		print ""
-	print "    default:"
-	print "      break;"
-	print "  }"
-	print "  return X;"
-	print "}"
-	print
+			print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset))
+		print ("      break;")
+		print ("")
+	print ("    default:")
+	print ("      break;")
+	print ("  }")
+	print ("  return X;")
+	print ("}")
+	print ()
 	for value,short in short_value.items():
-		print "#undef %s" % (short)
-	print
+		print ("#undef %s" % (short))
+	print ()
 
 def print_shaping_table(f):
 
 	shapes = {}
 	ligatures = {}
 	names = {}
 	for line in f:
 
@@ -181,89 +182,86 @@ def print_shaping_table(f):
 			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 "{"
+	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 0
 		     for shape in  ['initial', 'medial', 'final', 'isolated']]
 		value = ', '.join ("0x%04Xu" % c for c in s)
-		print "  {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
+		print ("  {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else ""))
 
-	print "};"
-	print
-	print "#define SHAPING_TABLE_FIRST	0x%04Xu" % min_u
-	print "#define SHAPING_TABLE_LAST	0x%04Xu" % max_u
-	print
+	print ("};")
+	print ()
+	print ("#define SHAPING_TABLE_FIRST	0x%04Xu" % min_u)
+	print ("#define SHAPING_TABLE_LAST	0x%04Xu" % 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 ligature_set_t {"
-	print " uint16_t first;"
-	print " struct ligature_pairs_t {"
-	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 ()
+	print ("static const struct ligature_set_t {")
+	print (" uint16_t first;")
+	print (" struct ligature_pairs_t {")
+	print ("   uint16_t second;")
+	print ("   uint16_t ligature;")
+	print (" } ligatures[%d];" % max_i)
+	print ("} ligature_table[] =")
+	print ("{")
+	for first in sorted (ligas.keys ()):
 
-		print "  { 0x%04Xu, {" % (first)
+		print ("  { 0x%04Xu, {" % (first))
 		for liga in ligas[first]:
-			print "    { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]])
-		print "  }},"
+			print ("    { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
+		print ("  }},")
 
-	print "};"
-	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 UnicodeData.txt Blocks.txt"
-print " *"
-print " * on files with these headers:"
-print " *"
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.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_ARABIC_TABLE_HH"
-print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
-print
+		print (" * %s" % (l.strip()))
+print (" */")
+print ()
+print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
+print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
+print ()
 
 read_blocks (files[2])
 print_joining_table (files[0])
 print_shaping_table (files[1])
 
-print
-print "#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */"
-print
-print "/* == End of generated table == */"
-
+print ()
+print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */")
+print ()
+print ("/* == End of generated table == */")
--- a/gfx/harfbuzz/src/gen-def.py
+++ b/gfx/harfbuzz/src/gen-def.py
@@ -1,18 +1,18 @@
 #!/usr/bin/env python
 
-from __future__ import print_function
+from __future__ import print_function, division, absolute_import
 
 import io, os, re, sys
 
 headers_content = []
 for h in os.environ["headers"].split (' '):
 	if h.endswith (".h"):
-		with io.open(h, encoding='utf8') as f: headers_content.append (f.read ())
+		with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
 
 result = """EXPORTS
 %s
 LIBRARY lib%s-0.dll""" % (
 	"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
 	sys.argv[1].replace ('.def', '')
 )
 
--- a/gfx/harfbuzz/src/gen-indic-table.py
+++ b/gfx/harfbuzz/src/gen-indic-table.py
@@ -1,14 +1,16 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
-import sys
+from __future__ import print_function, division, absolute_import
+
+import io, sys
 
 if len (sys.argv) != 4:
-	print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt"
+	print ("usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt", file=sys.stderr)
 	sys.exit (1)
 
 ALLOWED_SINGLES = [0x00A0, 0x25CC]
 ALLOWED_BLOCKS = [
 	'Basic Latin',
 	'Latin-1 Supplement',
 	'Devanagari',
 	'Bengali',
@@ -25,17 +27,17 @@ ALLOWED_BLOCKS = [
 	'Vedic Extensions',
 	'General Punctuation',
 	'Superscripts and Subscripts',
 	'Devanagari Extended',
 	'Myanmar Extended-B',
 	'Myanmar Extended-A',
 ]
 
-files = [file (x) for x in sys.argv[1:]]
+files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
 
 headers = [[f.readline () for i in range (2)] for f in files]
 
 data = [{} for f in files]
 values = [{} for f in files]
 for i, f in enumerate (files):
 	for line in f:
 
@@ -82,31 +84,31 @@ for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0
 		data[u][0] = "Vowel_Dependent"
 
 # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
 singles = {}
 for u in ALLOWED_SINGLES:
 	singles[u] = data[u]
 	del data[u]
 
-print "/* == Start of generated table == */"
-print "/*"
-print " * The following table is generated by running:"
-print " *"
-print " *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt"
-print " *"
-print " * on files with these headers:"
-print " *"
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" *   ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.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 '#include "hb-ot-shape-complex-indic-private.hh"'
-print
+		print (" * %s" % (l.strip()))
+print (" */")
+print ()
+print ('#include "hb-ot-shape-complex-indic-private.hh"')
+print ()
 
 # Shorten values
 short = [{
 	"Bindu":		'Bi',
 	"Cantillation_Mark":	'Ca',
 	"Joiner":		'ZWJ',
 	"Non_Joiner":		'ZWNJ',
 	"Number":		'Nd',
@@ -125,73 +127,71 @@ all_shorts = [{},{}]
 
 for i in range (2):
 	for v,s in short[i].items ():
 		all_shorts[i][s] = v
 
 what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
 what_short = ["ISC", "IMC"]
 for i in range (2):
-	print
-	vv = values[i].keys ()
-	vv.sort ()
+	print ()
+	vv = sorted (values[i].keys ())
 	for v in vv:
 		v_no_and = v.replace ('_And_', '_')
 		if v in short[i]:
 			s = short[i][v]
 		else:
 			s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')])
 			if s in all_shorts[i]:
 				raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
 			all_shorts[i][s] = v
 			short[i][v] = s
-		print "#define %s_%s	%s_%s	%s/* %3d chars; %s */" % \
-			(what_short[i], s, what[i], v.upper (), \
-			'	'* ((48-1 - len (what[i]) - 1 - len (v)) / 8), \
-			values[i][v], v)
-print
-print "#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)"
-print
-print
+		print ("#define %s_%s	%s_%s	%s/* %3d chars; %s */" %
+			(what_short[i], s, what[i], v.upper (),
+			'	'* ((48-1 - len (what[i]) - 1 - len (v)) // 8),
+			values[i][v], v))
+print ()
+print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
+print ()
+print ()
 
 total = 0
 used = 0
 last_block = None
 def print_block (block, start, end, data):
 	global total, used, last_block
 	if block and block != last_block:
-		print
-		print
-		print "  /* %s */" % block
+		print ()
+		print ()
+		print ("  /* %s */" % block)
 	num = 0
 	assert start % 8 == 0
 	assert (end+1) % 8 == 0
 	for u in range (start, end+1):
 		if u % 8 == 0:
-			print
-			print "  /* %04X */" % u,
+			print ()
+			print ("  /* %04X */" % u, end="")
 		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]])))
+		print ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])), end="")
 
 	total += end - start + 1
 	used += num
 	if block:
 		last_block = block
 
-uu = data.keys ()
-uu.sort ()
+uu = sorted (data.keys ())
 
 last = -100000
 num = 0
 offset = 0
 starts = []
 ends = []
-print "static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {"
+print ("static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {")
 for u in uu:
 	if u <= last:
 		continue
 	block = data[u][2]
 
 	start = u//8*8
 	end = start+1
 	while end in uu and block == data[end][2]:
@@ -201,60 +201,59 @@ for u in uu:
 	if start != last + 1:
 		if start - last <= 1+16*3:
 			print_block (None, last+1, start-1, data)
 			last = start-1
 		else:
 			if last >= 0:
 				ends.append (last + 1)
 				offset += ends[-1] - starts[-1]
-			print
-			print
-			print "#define indic_offset_0x%04xu %d" % (start, offset)
+			print ()
+			print ()
+			print ("#define indic_offset_0x%04xu %d" % (start, offset))
 			starts.append (start)
 
 	print_block (block, start, end, data)
 	last = end
 ends.append (last + 1)
 offset += ends[-1] - starts[-1]
-print
-print
+print ()
+print ()
 occupancy = used * 100. / total
 page_bits = 12
-print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
-print
-print "INDIC_TABLE_ELEMENT_TYPE"
-print "hb_indic_get_categories (hb_codepoint_t u)"
-print "{"
-print "  switch (u >> %d)" % page_bits
-print "  {"
-pages = set([u>>page_bits for u in starts+ends+singles.keys()])
+print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
+print ()
+print ("INDIC_TABLE_ELEMENT_TYPE")
+print ("hb_indic_get_categories (hb_codepoint_t u)")
+print ("{")
+print ("  switch (u >> %d)" % page_bits)
+print ("  {")
+pages = set ([u>>page_bits for u in starts+ends+list (singles.keys ())])
 for p in sorted(pages):
-	print "    case 0x%0Xu:" % p
+	print ("    case 0x%0Xu:" % p)
 	for u,d in singles.items ():
 		if p != u>>page_bits: continue
-		print "      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+		print ("      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]]))
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "indic_offset_0x%04xu" % start
-		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
-	print "      break;"
-	print ""
-print "    default:"
-print "      break;"
-print "  }"
-print "  return _(x,x);"
-print "}"
-print
-print "#undef _"
+		print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
+	print ("      break;")
+	print ("")
+print ("    default:")
+print ("      break;")
+print ("  }")
+print ("  return _(x,x);")
+print ("}")
+print ()
+print ("#undef _")
 for i in range (2):
 	print
-	vv = values[i].keys ()
-	vv.sort ()
+	vv = sorted (values[i].keys ())
 	for v in vv:
-		print "#undef %s_%s" % \
-			(what_short[i], short[i][v])
-print
-print "/* == End of generated table == */"
+		print ("#undef %s_%s" %
+			(what_short[i], short[i][v]))
+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/gen-unicode-ranges.py
+++ b/gfx/harfbuzz/src/gen-unicode-ranges.py
@@ -1,22 +1,24 @@
 # -*- coding: utf-8 -*-
 
 # Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
 # Input is a tab seperated list of unicode ranges from the otspec
 # (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1).
 
+from __future__ import print_function, division, absolute_import
+
 import io
 import re
 import sys
 
 reload(sys)
 sys.setdefaultencoding('utf-8')
 
-print (u"""static Range os2UnicodeRangesSorted[] =
+print ("""static Range os2UnicodeRangesSorted[] =
 {""")
 
 args = sys.argv[1:]
 input_file = args[0]
 
 with io.open(input_file, mode="r", encoding="utf-8") as f:
 
   all_ranges = [];
@@ -42,11 +44,11 @@ with io.open(input_file, mode="r", encod
 
 all_ranges = sorted(all_ranges, key=lambda t: t[0])
 
 for ranges in all_ranges:
   start = ("0x%X" % ranges[0]).rjust(8)
   end = ("0x%X" % ranges[1]).rjust(8)
   bit = ("%s" % ranges[2]).rjust(3)
 
-  print "  {%s, %s, %s}, // %s" % (start, end, bit, ranges[3])
+  print ("  {%s, %s, %s}, // %s" % (start, end, bit, ranges[3]))
 
-print (u"""};""");
+print ("""};""")
--- a/gfx/harfbuzz/src/gen-use-table.py
+++ b/gfx/harfbuzz/src/gen-use-table.py
@@ -1,19 +1,21 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
-import sys
+from __future__ import print_function, division, absolute_import
+
+import io, sys
 
 if len (sys.argv) != 5:
-	print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
+	print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
 	sys.exit (1)
 
 BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
 
-files = [file (x) for x in sys.argv[1:]]
+files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
 
 headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 2]
 headers.append (["UnicodeData.txt does not have a header."])
 
 data = [{} for f in files]
 values = [{} for f in files]
 for i, f in enumerate (files):
 	for line in f:
@@ -88,16 +90,17 @@ property_names = [
 	'Consonant_With_Stacker',
 	'Consonant_Prefixed',
 	'Consonant_Preceding_Repha',
 	'Consonant_Succeeding_Repha',
 	'Consonant_Subjoined',
 	'Consonant_Medial',
 	'Consonant_Final',
 	'Consonant_Head_Letter',
+	'Consonant_Initial_Postfixed',
 	'Modifying_Letter',
 	'Tone_Letter',
 	'Tone_Mark',
 	'Gemination_Mark',
 	'Cantillation_Mark',
 	'Register_Shifter',
 	'Syllable_Modifier',
 	'Consonant_Killer',
@@ -119,25 +122,32 @@ property_names = [
 	'Top_And_Left',
 	'Top_And_Left_And_Right',
 	'Bottom_And_Left',
 	'Bottom_And_Right',
 	'Top_And_Bottom_And_Right',
 	'Overstruck',
 ]
 
+try:
+	basestring
+except NameError:
+	basestring = str
+
 class PropertyValue(object):
 	def __init__(self, name_):
 		self.name = name_
 	def __str__(self):
 		return self.name
 	def __eq__(self, other):
 		return self.name == (other if isinstance(other, basestring) else other.name)
 	def __ne__(self, other):
 		return not (self == other)
+	def __hash__(self):
+		return hash(str(self))
 
 property_values = {}
 
 for name in property_names:
 	value = PropertyValue(name)
 	assert value not in property_values
 	assert value not in globals()
 	property_values[name] = value
@@ -150,29 +160,31 @@ def is_BASE(U, UISC, UGC):
 			Tone_Letter,
 			Vowel_Independent #SPEC-DRAFT
 			] or
 		(UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial,
 					Consonant_Subjoined, Vowel, Vowel_Dependent]))
 def is_BASE_IND(U, UISC, UGC):
 	#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
 	return (UISC in [Consonant_Dead, Modifying_Letter] or
-		(UGC == Po and not U in [0x104E, 0x2022, 0x11A3F, 0x11A45]) or
+		(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45]) or
 		False # SPEC-DRAFT-OUTDATED! U == 0x002D
 		)
 def is_BASE_NUM(U, UISC, UGC):
 	return UISC == Brahmi_Joining_Number
 def is_BASE_OTHER(U, UISC, UGC):
 	if UISC == Consonant_Placeholder: return True #SPEC-DRAFT
 	#SPEC-DRAFT return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
 	return U in [0x2015, 0x2022, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
 def is_CGJ(U, UISC, UGC):
 	return U == 0x034F
 def is_CONS_FINAL(U, UISC, UGC):
+	# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
 	return ((UISC == Consonant_Final and UGC != Lo) or
+		UISC == Consonant_Initial_Postfixed or
 		UISC == Consonant_Succeeding_Repha)
 def is_CONS_FINAL_MOD(U, UISC, UGC):
 	#SPEC-DRAFT return  UISC in [Consonant_Final_Modifier, Syllable_Modifier]
 	return  UISC == Syllable_Modifier
 def is_CONS_MED(U, UISC, UGC):
 	return UISC == Consonant_Medial and UGC != Lo
 def is_CONS_MOD(U, UISC, UGC):
 	return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
@@ -320,105 +332,105 @@ def map_to_use(data):
 		# Resolve Indic_Positional_Category
 
 		# TODO: Not in Unicode 8.0 yet, but in spec.
 		if U == 0x1B6C: UIPC = Bottom
 
 		# TODO: These should die, but have UIPC in Unicode 8.0
 		if U in [0x953, 0x954]: UIPC = Not_Applicable
 
-		# TODO: In USE's override list but not in Unicode 8.0
+		# TODO: In USE's override list but not in Unicode 11.0
 		if U == 0x103C: UIPC = Left
 
-		# TODO: These are not in USE's override list that we have, nor are they in Unicode 8.0
+		# TODO: These are not in USE's override list that we have, nor are they in Unicode 11.0
 		if 0xA926 <= U <= 0xA92A: UIPC = Top
 		if U == 0x111CA: UIPC = Bottom
 		if U == 0x11300: UIPC = Top
-		if U == 0x1133C: UIPC = Bottom
 		if U == 0x1171E: UIPC = Left # Correct?!
 		if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
 		if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
+		# https://github.com/roozbehp/unicode-data/issues/8
+		if U == 0x0A51: UIPC = Bottom
 
 		assert (UIPC in [Not_Applicable, Visual_Order_Left] or
 			USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
 
 		pos_mapping = use_positions.get(USE, None)
 		if pos_mapping:
 			values = [k for k,v in pos_mapping.items() if v and UIPC in v]
 			assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values)
 			USE = USE + values[0]
 
 		out[U] = (USE, UBlock)
 	return out
 
 defaults = ('O', 'No_Block')
 data = map_to_use(data)
 
-print "/* == Start of generated table == */"
-print "/*"
-print " * The following table is generated by running:"
-print " *"
-print " *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
-print " *"
-print " * on files with these headers:"
-print " *"
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" *   ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.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 '#include "hb-ot-shape-complex-use-private.hh"'
-print
+		print (" * %s" % (l.strip()))
+print (" */")
+print ()
+print ('#include "hb-ot-shape-complex-use-private.hh"')
+print ()
 
 total = 0
 used = 0
 last_block = None
 def print_block (block, start, end, data):
 	global total, used, last_block
 	if block and block != last_block:
-		print
-		print
-		print "  /* %s */" % block
+		print ()
+		print ()
+		print ("  /* %s */" % block)
 		if start % 16:
-			print ' ' * (20 + (start % 16 * 6)),
+			print (' ' * (20 + (start % 16 * 6)), end='')
 	num = 0
 	assert start % 8 == 0
 	assert (end+1) % 8 == 0
 	for u in range (start, end+1):
 		if u % 16 == 0:
-			print
-			print "  /* %04X */" % u,
+			print ()
+			print ("  /* %04X */" % u, end='')
 		if u in data:
 			num += 1
 		d = data.get (u, defaults)
-		sys.stdout.write ("%6s," % d[0])
+		print ("%6s," % d[0], end='')
 
 	total += end - start + 1
 	used += num
 	if block:
 		last_block = block
 
-uu = data.keys ()
-uu.sort ()
+uu = sorted (data.keys ())
 
 last = -100000
 num = 0
 offset = 0
 starts = []
 ends = []
 for k,v in sorted(use_mapping.items()):
 	if k in use_positions and use_positions[k]: continue
-	print "#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:])
+	print ("#define %s	USE_%s	/* %s */" % (k, k, v.__name__[3:]))
 for k,v in sorted(use_positions.items()):
 	if not v: continue
 	for suf in v.keys():
 		tag = k + suf
-		print "#define %s	USE_%s" % (tag, tag)
-print ""
-print "static const USE_TABLE_ELEMENT_TYPE use_table[] = {"
+		print ("#define %s	USE_%s" % (tag, tag))
+print ("")
+print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
 for u in uu:
 	if u <= last:
 		continue
 	block = data[u][1]
 
 	start = u//8*8
 	end = start+1
 	while end in uu and block == data[end][1]:
@@ -428,57 +440,57 @@ for u in uu:
 	if start != last + 1:
 		if start - last <= 1+16*3:
 			print_block (None, last+1, start-1, data)
 			last = start-1
 		else:
 			if last >= 0:
 				ends.append (last + 1)
 				offset += ends[-1] - starts[-1]
-			print
-			print
-			print "#define use_offset_0x%04xu %d" % (start, offset)
+			print ()
+			print ()
+			print ("#define use_offset_0x%04xu %d" % (start, offset))
 			starts.append (start)
 
 	print_block (block, start, end, data)
 	last = end
 ends.append (last + 1)
 offset += ends[-1] - starts[-1]
-print
-print
+print ()
+print ()
 occupancy = used * 100. / total
 page_bits = 12
-print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
-print
-print "USE_TABLE_ELEMENT_TYPE"
-print "hb_use_get_category (hb_codepoint_t u)"
-print "{"
-print "  switch (u >> %d)" % page_bits
-print "  {"
+print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
+print ()
+print ("USE_TABLE_ELEMENT_TYPE")
+print ("hb_use_get_category (hb_codepoint_t u)")
+print ("{")
+print ("  switch (u >> %d)" % page_bits)
+print ("  {")
 pages = set([u>>page_bits for u in starts+ends])
 for p in sorted(pages):
-	print "    case 0x%0Xu:" % p
+	print ("    case 0x%0Xu:" % p)
 	for (start,end) in zip (starts, ends):
 		if p not in [start>>page_bits, end>>page_bits]: continue
 		offset = "use_offset_0x%04xu" % start
-		print "      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
-	print "      break;"
-	print ""
-print "    default:"
-print "      break;"
-print "  }"
-print "  return USE_O;"
-print "}"
-print
+		print ("      if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset))
+	print ("      break;")
+	print ("")
+print ("    default:")
+print ("      break;")
+print ("  }")
+print ("  return USE_O;")
+print ("}")
+print ()
 for k in sorted(use_mapping.keys()):
 	if k in use_positions and use_positions[k]: continue
-	print "#undef %s" % k
+	print ("#undef %s" % k)
 for k,v in sorted(use_positions.items()):
 	if not v: continue
 	for suf in v.keys():
 		tag = k + suf
-		print "#undef %s" % tag
-print
-print "/* == End of generated table == */"
+		print ("#undef %s" % tag)
+print ()
+print ("/* == End of generated table == */")
 
 # Maintain at least 50% occupancy in the table */
 if occupancy < 50:
 	raise Exception ("Table too sparse, please investigate: ", occupancy)
deleted file mode 100644
--- a/gfx/harfbuzz/src/harfbuzz-icu.pc
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=/usr/local
-exec_prefix=/usr/local
-libdir=/usr/local/lib
-includedir=/usr/local/include
-
-Name: harfbuzz
-Description: HarfBuzz text shaping library ICU integration
-Version: 1.7.6
-
-Requires: harfbuzz
-Requires.private: icu-uc
-Libs: -L${libdir} -lharfbuzz-icu
-Cflags: -I${includedir}/harfbuzz
deleted file mode 100644
--- a/gfx/harfbuzz/src/harfbuzz-subset.pc
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=/usr/local
-exec_prefix=/usr/local
-libdir=/usr/local/lib
-includedir=/usr/local/include
-
-Name: harfbuzz
-Description: HarfBuzz font subsetter
-Version: 1.7.6
-
-Requires: harfbuzz
-Libs: -L${libdir} -lharfbuzz-subset
-Cflags: -I${includedir}/harfbuzz
deleted file mode 100644
--- a/gfx/harfbuzz/src/harfbuzz.pc
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=/usr/local
-exec_prefix=/usr/local
-libdir=/usr/local/lib
-includedir=/usr/local/include
-
-Name: harfbuzz
-Description: HarfBuzz text shaping library
-Version: 1.7.6
-
-Libs: -L${libdir} -lharfbuzz
-Libs.private: -lm    
-Requires.private: glib-2.0 >= 2.19.1 
-Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-fmtx-table.hh
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_FMTX_TABLE_HH
+#define HB_AAT_FMTX_TABLE_HH
+
+#include "hb-aat-layout-common-private.hh"
+
+/*
+ * fmtx -- Font Metrics
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fmtx.html
+ */
+#define HB_AAT_TAG_fmtx HB_TAG('f','m','t','x')
+
+
+namespace AAT {
+
+
+struct fmtx
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_fmtx;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  FixedVersion<>version;		/* Version (set to 0x00020000). */
+  HBUINT32	glyphIndex;		/* The glyph whose points represent the metrics. */
+  HBUINT8	horizontalBefore;	/* Point number for the horizontal ascent. */
+  HBUINT8	horizontalAfter;	/* Point number for the horizontal descent. */
+  HBUINT8	horizontalCaretHead;	/* Point number for the horizontal caret head. */
+  HBUINT8	horizontalCaretBase;	/* Point number for the horizontal caret base. */
+  HBUINT8	verticalBefore;		/* Point number for the vertical ascent. */
+  HBUINT8	verticalAfter;		/* Point number for the vertical descent. */
+  HBUINT8	verticalCaretHead;	/* Point number for the vertical caret head. */
+  HBUINT8	verticalCaretBase;	/* Point number for the vertical caret base. */
+  public:
+  DEFINE_SIZE_STATIC (16);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_FMTX_TABLE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-gcid-table.hh
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_GCID_TABLE_HH
+#define HB_AAT_GCID_TABLE_HH
+
+#include "hb-aat-layout-common-private.hh"
+
+/*
+ * gcid -- Glyphs CIDs
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gcid.html
+ */
+#define HB_AAT_TAG_gcid HB_TAG('g','c','i','d')
+
+
+namespace AAT {
+
+
+struct gcid
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_gcid;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && CIDs.sanitize (c)));
+  }
+
+  protected:
+  HBUINT16	version;	/* Version number (set to 0) */
+  HBUINT16	format;		/* Data format (set to 0) */
+  HBUINT32	size;		/* Size of the table, including header */
+  HBUINT16	registry;	/* The registry ID */
+  HBUINT8	registryName[64];
+				/* The registry name in ASCII */
+  HBUINT16	order;		/* The order ID */
+  HBUINT8	orderName[64];	/* The order name in ASCII */
+  HBUINT16	supplementVersion;
+				/* The supplement version */
+  ArrayOf<HBUINT16>
+		CIDs;		/* The CIDs for the glyphs in the font,
+				 * starting with glyph 0. If a glyph does not correspond
+				 * to a CID in the identified collection, 0xFFFF is used.
+				 * This should not exceed the number of glyphs in the font. */
+  public:
+  DEFINE_SIZE_ARRAY (144, CIDs);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_GCID_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-aat-layout-ankr-table.hh
+++ b/gfx/harfbuzz/src/hb-aat-layout-ankr-table.hh
@@ -22,26 +22,26 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
 
 #ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
 #define HB_AAT_LAYOUT_ANKR_TABLE_HH
 
 #include "hb-aat-layout-common-private.hh"
 
+/*
+ * ankr -- Anchor Point
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html
+ */
 #define HB_AAT_TAG_ankr HB_TAG('a','n','k','r')
 
 
 namespace AAT {
 
 
-/*
- * ankr -- Anchor point
- */
-
 struct Anchor
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this));
   }
 
@@ -53,27 +53,29 @@ struct Anchor
 
 struct ankr
 {
   static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && version == 0 &&
-		  lookupTable.sanitize (c, this) &&
-		  anchors.sanitize (c, this));
+    return_trace (likely (c->check_struct (this) &&
+			  version == 0 &&
+			  lookupTable.sanitize (c, this) &&
+			  anchors.sanitize (c, this)));
   }
 
   protected:
-  HBUINT16			version; 	/* Version number (set to zero) */
-  HBUINT16			flags;		/* Flags (currently unused; set to zero) */
-  LOffsetTo<Lookup<HBUINT16> >	lookupTable;	/* Offset to the table's lookup table */
-  LOffsetTo<ArrayOf<Anchor, HBUINT32> >
-				anchors;	/* Offset to the glyph data table */
+  HBUINT16	version; 	/* Version number (set to zero) */
+  HBUINT16	flags;		/* Flags (currently unused; set to zero) */
+  LOffsetTo<Lookup<HBUINT16> >
+		lookupTable;	/* Offset to the table's lookup table */
+  LOffsetTo<LArrayOf<Anchor> >
+		anchors;	/* Offset to the glyph data table */
 
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 } /* namespace AAT */
 
 
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout-bsln-table.hh
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH
+#define HB_AAT_LAYOUT_BSLN_TABLE_HH
+
+#include "hb-aat-layout-common-private.hh"
+
+/*
+ * bsln -- Baseline
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html
+ */
+#define HB_AAT_TAG_bsln HB_TAG('b','s','l','n')
+
+
+namespace AAT {
+
+
+struct BaselineTableFormat0Part
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  protected:
+  // Roman, Ideographic centered, Ideographic low, Hanging and Math
+  // are the default defined ones, but any other maybe accessed also.
+  HBINT16	deltas[32];	/* These are the FUnit distance deltas from
+				 * the font's natural baseline to the other
+				 * baselines used in the font. */
+  public:
+  DEFINE_SIZE_STATIC (64);
+};
+
+struct BaselineTableFormat1Part
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  lookupTable.sanitize (c)));
+  }
+
+  protected:
+  HBINT16	deltas[32];	/* ditto */
+  Lookup<HBUINT16>
+		lookupTable;	/* Lookup table that maps glyphs to their
+				 * baseline values. */
+  public:
+  DEFINE_SIZE_MIN (66);
+};
+
+struct BaselineTableFormat2Part
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  protected:
+  GlyphID	stdGlyph;	/* The specific glyph index number in this
+				 * font that is used to set the baseline values.
+				 * This is the standard glyph.
+				 * This glyph must contain a set of control points
+				 * (whose numbers are contained in the ctlPoints field)
+				 * that are used to determine baseline distances. */
+  HBUINT16	ctlPoints[32];	/* Set of control point numbers,
+				 * associated with the standard glyph.
+				 * A value of 0xFFFF means there is no corresponding
+				 * control point in the standard glyph. */
+  public:
+  DEFINE_SIZE_STATIC (66);
+};
+
+struct BaselineTableFormat3Part
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && lookupTable.sanitize (c));
+  }
+
+  protected:
+  GlyphID	stdGlyph;	/* ditto */
+  HBUINT16	ctlPoints[32];	/* ditto */
+  Lookup<HBUINT16>
+		lookupTable;	/* Lookup table that maps glyphs to their
+				 * baseline values. */
+  public:
+  DEFINE_SIZE_MIN (68);
+};
+
+struct bsln
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_bsln;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
+      return_trace (false);
+
+    switch (format) {
+    case 0: return_trace (parts.format0.sanitize (c));
+    case 1: return_trace (parts.format1.sanitize (c));
+    case 2: return_trace (parts.format2.sanitize (c));
+    case 3: return_trace (parts.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  FixedVersion<>version;	/* Version number of the Baseline table. */
+  HBUINT16	format;		/* Format of the baseline table. Only one baseline
+				 * format may be selected for the font. */
+  HBUINT16	defaultBaseline;/* Default baseline value for all glyphs.
+				 * This value can be from 0 through 31. */
+  union {
+  // Distance-Based Formats
+  BaselineTableFormat0Part	format0;
+  BaselineTableFormat1Part	format1;
+  // Control Point-based Formats
+  BaselineTableFormat2Part	format2;
+  BaselineTableFormat3Part	format3;
+  } parts;
+  public:
+  DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LAYOUT_BSLN_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-aat-layout-common-private.hh
+++ b/gfx/harfbuzz/src/hb-aat-layout-common-private.hh
@@ -62,38 +62,38 @@ struct BinSearchHeader
 };
 
 template <typename Type>
 struct BinSearchArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
   {
     if (unlikely (i >= header.nUnits)) return Null(Type);
-    return StructAtOffset<Type> (bytes, i * header.unitSize);
+    return StructAtOffset<Type> (bytesZ, i * header.unitSize);
   }
   inline Type& operator [] (unsigned int i)
   {
-    return StructAtOffset<Type> (bytes, i * header.unitSize);
+    return StructAtOffset<Type> (bytesZ, i * header.unitSize);
   }
   inline unsigned int get_size (void) const
   { return header.static_size + header.nUnits * header.unitSize; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
 
     /* Note: for structs that do not reference other structs,
      * we do not need to call their sanitize() as we already did
      * a bound check on the aggregate array size.  We just include
      * a small unreachable expression to make sure the structs
      * pointed to do have a simple sanitize(), ie. they do not
      * reference other structs via offsets.
      */
-    (void) (false && StructAtOffset<Type> (bytes, 0).sanitize (c));
+    (void) (false && StructAtOffset<Type> (bytesZ, 0).sanitize (c));
 
     return_trace (true);
   }
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
     unsigned int count = header.nUnits;
@@ -106,17 +106,17 @@ struct BinSearchArrayOf
   template <typename T>
   inline const Type *bsearch (const T &key) const
   {
     unsigned int size = header.unitSize;
     int min = 0, max = (int) header.nUnits - 1;
     while (min <= max)
     {
       int mid = (min + max) / 2;
-      const Type *p = (const Type *) (((const char *) bytes) + (mid * size));
+      const Type *p = (const Type *) (((const char *) bytesZ) + (mid * size));
       int c = p->cmp (key);
       if (c < 0)
 	max = mid - 1;
       else if (c > 0)
 	min = mid + 1;
       else
 	return p;
     }
@@ -124,108 +124,24 @@ struct BinSearchArrayOf
   }
 
   private:
   inline bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     return_trace (header.sanitize (c) &&
 		  Type::static_size >= header.unitSize &&
-		  c->check_array (bytes, header.unitSize, header.nUnits));
+		  c->check_array (bytesZ, header.unitSize, header.nUnits));
   }
 
   protected:
   BinSearchHeader	header;
-  HBUINT8			bytes[VAR];
+  HBUINT8		bytesZ[VAR];
   public:
-  DEFINE_SIZE_ARRAY (10, bytes);
-};
-
-
-/* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf,
- * and other places around the code base?? */
-template <typename Type>
-struct UnsizedArrayOf
-{
-  inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
-  inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-
-    /* Note: for structs that do not reference other structs,
-     * we do not need to call their sanitize() as we already did
-     * a bound check on the aggregate array size.  We just include
-     * a small unreachable expression to make sure the structs
-     * pointed to do have a simple sanitize(), ie. they do not
-     * reference other structs via offsets.
-     */
-    (void) (false && arrayZ[0].sanitize (c));
-
-    return_trace (true);
-  }
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base)))
-        return_trace (false);
-    return_trace (true);
-  }
-  template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
-    for (unsigned int i = 0; i < count; i++)
-      if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
-        return_trace (false);
-    return_trace (true);
-  }
-
-  private:
-  inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
-  }
-
-  public:
-  Type	arrayZ[VAR];
-  public:
-  DEFINE_SIZE_ARRAY (0, arrayZ);
-};
-
-/* Unsized array of offset's */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
-
-/* Unsized array of offsets relative to the beginning of the array itself. */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
-{
-  inline const Type& operator [] (unsigned int i) const
-  {
-    return this+this->arrayZ[i];
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
-  }
-  template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
-  }
+  DEFINE_SIZE_ARRAY (10, bytesZ);
 };
 
 
 /*
  * Lookup Table
  */
 
 template <typename T> struct Lookup;
@@ -590,21 +506,21 @@ struct StateTable
       *num_entries_out = num_entries;
 
     return_trace (true);
   }
 
   protected:
   HBUINT32	nClasses;	/* Number of classes, which is the number of indices
 				 * in a single line in the state array. */
-  OffsetTo<Lookup<HBUINT16>, HBUINT32>
+  LOffsetTo<Lookup<HBUINT16> >
 		classTable;	/* Offset to the class table. */
-  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
+  LOffsetTo<UnsizedArrayOf<HBUINT16> >
 		stateArrayTable;/* Offset to the state array. */
-  OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT32>
+  LOffsetTo<UnsizedArrayOf<Entry<Extra> > >
 		entryTable;	/* Offset to the entry array. */
 
   public:
   DEFINE_SIZE_STATIC (16);
 };
 
 template <typename EntryData>
 struct StateTableDriver
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-layout-feat-table.hh
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
+#define HB_AAT_LAYOUT_FEAT_TABLE_HH
+
+#include "hb-aat-layout-common-private.hh"
+
+/*
+ * feat -- Feature Name
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html
+ */
+#define HB_AAT_TAG_feat HB_TAG('f','e','a','t')
+
+
+namespace AAT {
+
+
+struct SettingName
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this)));
+  }
+
+  protected:
+  HBUINT16	setting;	/* The setting. */
+  NameID	nameIndex;	/* The name table index for the setting's name. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct FeatureName
+{
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  (base+settingTable).sanitize (c, nSettings)));
+  }
+
+  enum {
+    Exclusive = 0x8000,		/* If set, the feature settings are mutually exclusive. */
+    NotDefault = 0x4000,	/* If clear, then the setting with an index of 0 in
+				 * the setting name array for this feature should
+				 * be taken as the default for the feature
+				 * (if one is required). If set, then bits 0-15 of this
+				 * featureFlags field contain the index of the setting
+				 * which is to be taken as the default. */
+    IndexMask = 0x00FF		/* If bits 30 and 31 are set, then these sixteen bits
+				 * indicate the index of the setting in the setting name
+				 * array for this feature which should be taken
+				 * as the default. */
+  };
+
+  protected:
+  HBUINT16	feature;	/* Feature type. */
+  HBUINT16	nSettings;	/* The number of records in the setting name array. */
+  LOffsetTo<UnsizedArrayOf<SettingName> >
+		settingTable;	/* Offset in bytes from the beginning of this table to
+				 * this feature's setting name array. The actual type of
+				 * record this offset refers to will depend on the
+				 * exclusivity value, as described below. */
+  HBUINT16	featureFlags;	/* Single-bit flags associated with the feature type. */
+  HBINT16	nameIndex;	/* The name table index for the feature's name.
+				 * This index has values greater than 255 and
+				 * less than 32768. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+struct feat
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_feat;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+			  names.sanitize (c, featureNameCount, this)));
+  }
+
+  protected:
+  FixedVersion<>version;	/* Version number of the feature name table
+				 * (0x00010000 for the current version). */
+  HBUINT16	featureNameCount;
+				/* The number of entries in the feature name array. */
+  HBUINT16	reserved1;	/* Reserved (set to zero). */
+  HBUINT32	reserved2;	/* Reserved (set to zero). */
+  UnsizedArrayOf<FeatureName>
+		names;		/* The feature name array. */
+  public:
+  DEFINE_SIZE_STATIC (24);
+};
+
+} /* namespace AAT */
+
+#endif /* HB_AAT_LAYOUT_FEAT_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-aat-layout-kerx-table.hh
+++ b/gfx/harfbuzz/src/hb-aat-layout-kerx-table.hh
@@ -25,31 +25,36 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
 #define HB_AAT_LAYOUT_KERX_TABLE_HH
 
 #include "hb-open-type-private.hh"
 #include "hb-aat-layout-common-private.hh"
+#include "hb-aat-layout-ankr-table.hh"
 
-#define HB_AAT_TAG_KERX HB_TAG('k','e','r','x')
+/*
+ * kerx -- Extended Kerning
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
+ */
+#define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
 
 
 namespace AAT {
 
 using namespace OT;
 
 
 struct KerxFormat0Records
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
+    return_trace (likely (c->check_struct (this)));
   }
 
   protected:
   GlyphID	left;
   GlyphID	right;
   FWORD		value;
   public:
   DEFINE_SIZE_STATIC (6);
@@ -65,41 +70,42 @@ struct KerxSubTableFormat0
   //   if (i == -1)
   //     return 0;
   //   return pairs[i].get_kerning ();
   // }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-      c->check_array (records, records[0].static_size, nPairs));
+    return_trace (likely (c->check_struct (this) &&
+			  recordsZ.sanitize (c, nPairs)));
   }
 
   protected:
   // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is
   // needed here to use HBUINT32 instead
-  HBUINT32 nPairs;	/* The number of kerning pairs in this subtable */
-  HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs,
-                         * multiplied by the size in bytes of an entry in the subtable. */
-  HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less
-                           * than or equal to the value of nPairs. */
-  HBUINT32 rangeShift;	/* The value of nPairs minus the largest power of two less than or equal to nPairs. */
-  KerxFormat0Records records[VAR]; /* VAR=nPairs */
+  HBUINT32	nPairs;		/* The number of kerning pairs in this subtable */
+  HBUINT32	searchRange;	/* The largest power of two less than or equal to the value of nPairs,
+				 * multiplied by the size in bytes of an entry in the subtable. */
+  HBUINT32	entrySelector;	/* This is calculated as log2 of the largest power of two less
+				 * than or equal to the value of nPairs. */
+  HBUINT32	rangeShift;	/* The value of nPairs minus the largest power of two less than or equal to nPairs. */
+  UnsizedArrayOf<KerxFormat0Records>
+		recordsZ;	/* VAR=nPairs */
   public:
-  DEFINE_SIZE_ARRAY (16, records);
+  DEFINE_SIZE_ARRAY (16, recordsZ);
 };
 
 struct KerxSubTableFormat1
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-      stateHeader.sanitize (c));
+    return_trace (likely (c->check_struct (this) &&
+			  stateHeader.sanitize (c)));
   }
 
   protected:
   StateTable<HBUINT16>		stateHeader;
   LOffsetTo<ArrayOf<HBUINT16> >	valueTable;
   public:
   DEFINE_SIZE_STATIC (20);
 };
@@ -107,17 +113,18 @@ struct KerxSubTableFormat1
 // TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>?
 struct KerxClassTable
 {
   inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
+    return_trace (likely (firstGlyph.sanitize (c) &&
+			  classes.sanitize (c)));
   }
 
   protected:
   HBUINT16		firstGlyph;	/* First glyph in class range. */
   ArrayOf<HBUINT16>	classes;	/* Glyph classes. */
   public:
   DEFINE_SIZE_ARRAY (4, classes);
 };
@@ -136,21 +143,21 @@ struct KerxSubTableFormat2
     if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
       return 0;
     return *v;
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-      rowWidth.sanitize (c) &&
-		  leftClassTable.sanitize (c, this) &&
-		  rightClassTable.sanitize (c, this) &&
-		  array.sanitize (c, this));
+    return_trace (likely (c->check_struct (this) &&
+			  rowWidth.sanitize (c) &&
+			  leftClassTable.sanitize (c, this) &&
+			  rightClassTable.sanitize (c, this) &&
+			  array.sanitize (c, this)));
   }
 
   protected:
   HBUINT32	rowWidth;	/* The width, in bytes, of a row in the table. */
   LOffsetTo<KerxClassTable>
 		leftClassTable;	/* Offset from beginning of this subtable to
 				 * left-hand class table. */
   LOffsetTo<KerxClassTable>
@@ -163,21 +170,21 @@ struct KerxSubTableFormat2
   DEFINE_SIZE_STATIC (16);
 };
 
 struct KerxSubTableFormat4
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-      rowWidth.sanitize (c) &&
-		  leftClassTable.sanitize (c, this) &&
-		  rightClassTable.sanitize (c, this) &&
-		  array.sanitize (c, this));
+    return_trace (likely (c->check_struct (this) &&
+			  rowWidth.sanitize (c) &&
+			  leftClassTable.sanitize (c, this) &&
+			  rightClassTable.sanitize (c, this) &&
+			  array.sanitize (c, this)));
   }
 
   protected:
   HBUINT32	rowWidth;	/* The width, in bytes, of a row in the table. */
   LOffsetTo<KerxClassTable>
 		leftClassTable;	/* Offset from beginning of this subtable to
 				 * left-hand class table. */
   LOffsetTo<KerxClassTable>
@@ -190,21 +197,21 @@ struct KerxSubTableFormat4
   DEFINE_SIZE_STATIC (16);
 };
 
 struct KerxSubTableFormat6
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) &&
-      rowIndexTable.sanitize (c, this) &&
-      columnIndexTable.sanitize (c, this) &&
-      kerningArray.sanitize (c, this) &&
-      kerningVector.sanitize (c, this));
+    return_trace (likely (c->check_struct (this) &&
+			  rowIndexTable.sanitize (c, this) &&
+			  columnIndexTable.sanitize (c, this) &&
+			  kerningArray.sanitize (c, this) &&
+			  kerningVector.sanitize (c, this)));
   }
 
   protected:
   HBUINT32	flags;
   HBUINT16	rowCount;
   HBUINT16	columnCount;
   LOffsetTo<Lookup<HBUINT16> >	rowIndexTable;
   LOffsetTo<Lookup<HBUINT16> >	columnIndexTable;
@@ -231,17 +238,17 @@ struct KerxTable
     return_trace (false);
   }
 
   inline unsigned int get_size (void) const { return length; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!c->check_struct (this))
+    if (unlikely (!c->check_struct (this)))
       return_trace (false);
 
     switch (format) {
     case 0: return u.format0.sanitize (c);
     case 1: return u.format1.sanitize (c);
     case 2: return u.format2.sanitize (c);
     case 4: return u.format4.sanitize (c);
     case 6: return u.format6.sanitize (c);
@@ -266,53 +273,53 @@ public:
   DEFINE_SIZE_MIN (12);
 };
 
 struct SubtableGlyphCoverageArray
 {
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this));
+    return_trace (likely (c->check_struct (this)));
   }
 
   protected:
   HBUINT32	length;
   HBUINT32	coverage;
   HBUINT32	tupleCount;
   public:
   DEFINE_SIZE_STATIC (12);
 };
 
 struct kerx
 {
-  static const hb_tag_t tableTag = HB_AAT_TAG_KERX;
+  static const hb_tag_t tableTag = HB_AAT_TAG_kerx;
 
   inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
   {
     TRACE_APPLY (this);
     const KerxTable &table = StructAfter<KerxTable> (*this);
     return_trace (table.apply (c, ankr));
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    if (!(c->check_struct (this)))
+    if (unlikely (!(c->check_struct (this))))
      return_trace (false);
 
     /* TODO: Something like `morx`s ChainSubtable should be done here instead */
     const KerxTable *table = &StructAfter<KerxTable> (*this);
-    if (!(table->sanitize (c)))
+    if (unlikely (!(table->sanitize (c))))
       return_trace (false);
 
     for (unsigned int i = 0; i < nTables - 1; ++i)
     {
       table = &StructAfter<KerxTable> (*table);
-      if (!(table->sanitize (c)))
+      if (unlikely (!(table->sanitize (c))))
         return_trace (false);
     }
 
     // If version is less than 3, we are done here; otherwise better to check footer also
     if (version < 3)
       return_trace (true);
 
     // TODO: Investigate why this just work on some fonts no matter of version
@@ -322,17 +329,17 @@ struct kerx
 
     return_trace (true);
   }
 
   protected:
   HBUINT16		version;
   HBUINT16		padding;
   HBUINT32		nTables;
-/*KerxTable tables[VAR];*/
+/*KerxTable tablesZ[VAR]; XXX ArrayOf??? */
 /*SubtableGlyphCoverageArray coverage_array;*/
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 } /* namespace AAT */
 
 
--- a/gfx/harfbuzz/src/hb-aat-layout-morx-table.hh
+++ b/gfx/harfbuzz/src/hb-aat-layout-morx-table.hh
@@ -24,18 +24,23 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_AAT_LAYOUT_MORX_TABLE_HH
 #define HB_AAT_LAYOUT_MORX_TABLE_HH
 
 #include "hb-open-type-private.hh"
 #include "hb-aat-layout-common-private.hh"
+#include "hb-ot-layout-common-private.hh"
 
-#define HB_AAT_TAG_MORX HB_TAG('m','o','r','x')
+/*
+ * morx -- Extended Glyph Metamorphosis
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
+ */
+#define HB_AAT_TAG_morx HB_TAG('m','o','r','x')
 
 
 namespace AAT {
 
 using namespace OT;
 
 
 struct RearrangementSubtable
@@ -297,19 +302,20 @@ struct ContextualSubtable
       if (data.currentIndex != 0xFFFF)
 	num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
     }
 
     return_trace (substitutionTables.sanitize (c, this, num_lookups));
   }
 
   protected:
-  StateTable<EntryData>	machine;
-  OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32>, HBUINT32>
-			substitutionTables;
+  StateTable<EntryData>
+		machine;
+  LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> >
+		substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
 };
 
 struct LigatureSubtable
 {
   struct EntryData
   {
@@ -456,22 +462,23 @@ struct LigatureSubtable
   {
     TRACE_SANITIZE (this);
     /* The rest of array sanitizations are done at run-time. */
     return_trace (c->check_struct (this) && machine.sanitize (c) &&
 		  ligAction && component && ligature);
   }
 
   protected:
-  StateTable<EntryData>	machine;
-  OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT32>
+  StateTable<EntryData>
+		machine;
+  LOffsetTo<UnsizedArrayOf<HBUINT32> >
 		ligAction;	/* Offset to the ligature action table. */
-  OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
+  LOffsetTo<UnsizedArrayOf<HBUINT16> >
 		component;	/* Offset to the component table. */
-  OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT32>
+  LOffsetTo<UnsizedArrayOf<GlyphID> >
 		ligature;	/* Offset to the actual ligature lists. */
   public:
   DEFINE_SIZE_STATIC (28);
 };
 
 struct NoncontextualSubtable
 {
   inline bool apply (hb_aat_apply_context_t *c) const
@@ -658,70 +665,70 @@ struct Chain
 
   protected:
   HBUINT32	defaultFlags;	/* The default specification for subtables. */
   HBUINT32	length;		/* Total byte count, including this header. */
   HBUINT32	featureCount;	/* Number of feature subtable entries. */
   HBUINT32	subtableCount;	/* The number of subtables in the chain. */
 
   Feature	featureZ[VAR];	/* Features. */
-  ChainSubtable	subtableX[VAR];	/* Subtables. */
-  // subtableGlyphCoverageArray if major == 3
+/*ChainSubtable	subtableX[VAR];*//* Subtables. */
+/*subtableGlyphCoverageArray*/	/* Only if major == 3. */
 
   public:
   DEFINE_SIZE_MIN (16);
 };
 
 
 /*
  * The 'mort'/'morx' Tables
  */
 
 struct morx
 {
-  static const hb_tag_t tableTag = HB_AAT_TAG_MORX;
+  static const hb_tag_t tableTag = HB_AAT_TAG_morx;
 
   inline void apply (hb_aat_apply_context_t *c) const
   {
     c->set_lookup_index (0);
-    const Chain *chain = chains;
+    const Chain *chain = chainsZ;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
       chain->apply (c);
       chain = &StructAfter<Chain> (*chain);
     }
   }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
     if (!version.sanitize (c) ||
 	(version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 ||
 	!chainCount.sanitize (c))
       return_trace (false);
 
-    const Chain *chain = chains;
+    const Chain *chain = chainsZ;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     {
       if (!chain->sanitize (c, version.major))
 	return_trace (false);
       chain = &StructAfter<Chain> (*chain);
     }
 
     return_trace (true);
   }
 
   protected:
   FixedVersion<>version;	/* Version number of the glyph metamorphosis table.
 				 * 1 for mort, 2 or 3 for morx. */
   HBUINT32	chainCount;	/* Number of metamorphosis chains contained in this
 				 * table. */
-  Chain		chains[VAR];	/* Chains. */
+  Chain		chainsZ[VAR];	/* Chains. */
 
   public:
   DEFINE_SIZE_MIN (8);
 };
 
 } /* namespace AAT */
 
 
--- a/gfx/harfbuzz/src/hb-aat-layout-trak-table.hh
+++ b/gfx/harfbuzz/src/hb-aat-layout-trak-table.hh
@@ -24,48 +24,58 @@
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
 #define HB_AAT_LAYOUT_TRAK_TABLE_HH
 
 #include "hb-aat-layout-common-private.hh"
+#include "hb-ot-layout-private.hh"
 #include "hb-open-type-private.hh"
 
+/*
+ * trak -- Tracking
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
+ */
 #define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
 
 
 namespace AAT {
 
 
 struct TrackTableEntry
 {
-  inline bool sanitize (hb_sanitize_context_t *c, const void *base, unsigned int size) const
+  friend struct TrackData;
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base,
+			unsigned int size) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && (values.sanitize (c, base, size)));
+    return_trace (likely (c->check_struct (this) &&
+			  (valuesZ.sanitize (c, base, size))));
   }
 
+  private:
   inline float get_track_value () const
   {
     return track.to_float ();
   }
 
   inline int get_value (const void *base, unsigned int index) const
   {
-    return (base+values)[index];
+    return (base+valuesZ)[index];
   }
 
   protected:
-  Fixed			track;		/* Track value for this record. */
-  HBUINT16		trackNameID;	/* The 'name' table index for this track */
+  Fixed		track;		/* Track value for this record. */
+  NameID	trackNameID;	/* The 'name' table index for this track */
   OffsetTo<UnsizedArrayOf<FWORD> >
-			values;		/* Offset from start of tracking table to
-					 * per-size tracking values for this track. */
+		valuesZ;	/* Offset from start of tracking table to
+				 * per-size tracking values for this track. */
 
   public:
   DEFINE_SIZE_STATIC (8);
 };
 
 struct TrackData
 {
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -89,17 +99,17 @@ struct TrackData
 
     /* XXX Clean this up. Make it work with nSizes==1 and 0. */
 
     unsigned int sizes = nSizes;
 
     const TrackTableEntry *trackTableEntry = nullptr;
     for (unsigned int i = 0; i < sizes; ++i)
       // For now we only seek for track entries with zero tracking value
-      if (trackTable[i].get_track_value () == 0.)
+      if (trackTable[i].get_track_value () == 0.f)
         trackTableEntry = &trackTable[0];
 
     // We couldn't match any, exit
     if (!trackTableEntry) return 0.;
 
     /* TODO bfind() */
     unsigned int size_index;
     UnsizedArrayOf<Fixed> size_table = base+sizeTable;
@@ -112,51 +122,51 @@ struct TrackData
     if (size_index == sizes)
       return trackTableEntry->get_value (base, sizes - 1);
     if (size_index == 0 || size_table[size_index] == fixed_size)
       return trackTableEntry->get_value (base, size_index);
 
     float s0 = size_table[size_index - 1].to_float ();
     float s1 = size_table[size_index].to_float ();
     float t = (csspx - s0) / (s1 - s0);
-    return t * trackTableEntry->get_value (base, size_index) +
-      (1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
+    return (float) t * trackTableEntry->get_value (base, size_index) +
+	   ((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
   }
 
   protected:
-  HBUINT16		nTracks;	/* Number of separate tracks included in this table. */
-  HBUINT16		nSizes;		/* Number of point sizes included in this table. */
-  LOffsetTo<UnsizedArrayOf<Fixed> >	/* Offset to array[nSizes] of size values. */
-			sizeTable;
+  HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
+  HBUINT16	nSizes;		/* Number of point sizes included in this table. */
+  LOffsetTo<UnsizedArrayOf<Fixed> >
+		sizeTable;	/* Offset to array[nSizes] of size values. */
   UnsizedArrayOf<TrackTableEntry>
-			trackTable;	/* Array[nTracks] of TrackTableEntry records. */
+		trackTable;	/* Array[nTracks] of TrackTableEntry records. */
 
   public:
   DEFINE_SIZE_ARRAY (8, trackTable);
 };
 
 struct trak
 {
   static const hb_tag_t tableTag = HB_AAT_TAG_trak;
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
 
-    return_trace (c->check_struct (this) &&
-		  horizData.sanitize (c, this, this) &&
-		  vertData.sanitize (c, this, this));
+    return_trace (unlikely (c->check_struct (this) &&
+			    horizData.sanitize (c, this, this) &&
+			    vertData.sanitize (c, this, this)));
   }
 
   inline bool apply (hb_aat_apply_context_t *c) const
   {
     TRACE_APPLY (this);
 
     const float ptem = c->font->ptem;
-    if (ptem <= 0.f)
+    if (unlikely (ptem <= 0.f))
       return_trace (false);
 
     hb_buffer_t *buffer = c->buffer;
     if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
     {
       const TrackData &trackData = this+horizData;
       float tracking = trackData.get_tracking (this, ptem);
       hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
--- a/gfx/harfbuzz/src/hb-aat-layout.cc
+++ b/gfx/harfbuzz/src/hb-aat-layout.cc
@@ -26,118 +26,129 @@
 
 #include "hb-open-type-private.hh"
 
 #include "hb-ot-layout-private.hh"
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 #include "hb-aat-layout-private.hh"
 #include "hb-aat-layout-ankr-table.hh"
+#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise.
 #include "hb-aat-layout-kerx-table.hh"
 #include "hb-aat-layout-morx-table.hh"
 #include "hb-aat-layout-trak-table.hh"
+#include "hb-aat-fmtx-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-aat-gcid-table.hh" // Just so we compile it; unused otherwise.
+#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
 
 /*
  * morx/kerx/trak
  */
 
+#if 0
 static inline const AAT::ankr&
 _get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
   {
     if (blob)
       *blob = hb_blob_get_empty ();
-    return OT::Null(AAT::ankr);
+    return Null(AAT::ankr);
   }
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
   const AAT::ankr& ankr = *(layout->ankr.get ());
   if (blob)
     *blob = layout->ankr.blob;
   return ankr;
 }
 
 static inline const AAT::kerx&
 _get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
   {
     if (blob)
       *blob = hb_blob_get_empty ();
-    return OT::Null(AAT::kerx);
+    return Null(AAT::kerx);
   }
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
   /* XXX this doesn't call set_num_glyphs on sanitizer. */
   const AAT::kerx& kerx = *(layout->kerx.get ());
   if (blob)
     *blob = layout->kerx.blob;
   return kerx;
 }
 
 static inline const AAT::morx&
 _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
   {
     if (blob)
       *blob = hb_blob_get_empty ();
-    return OT::Null(AAT::morx);
+    return Null(AAT::morx);
   }
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
   /* XXX this doesn't call set_num_glyphs on sanitizer. */
   const AAT::morx& morx = *(layout->morx.get ());
   if (blob)
     *blob = layout->morx.blob;
   return morx;
 }
 
 static inline const AAT::trak&
 _get_trak (hb_face_t *face, hb_blob_t **blob = nullptr)
 {
   if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
   {
     if (blob)
       *blob = hb_blob_get_empty ();
-    return OT::Null(AAT::trak);
+    return Null(AAT::trak);
   }
   hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
   const AAT::trak& trak = *(layout->trak.get ());
   if (blob)
     *blob = layout->trak.blob;
   return trak;
 }
+#endif
 
 // static inline void
 // _hb_aat_layout_create (hb_face_t *face)
 // {
 //   OT::Sanitizer<AAT::morx> sanitizer;
 //   sanitizer.set_num_glyphs (face->get_num_glyphs ());
-//   hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX));
-//   OT::Sanitizer<AAT::morx>::lock_instance (morx_blob);
+//   hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_morx));
+//   morx_blob->as<AAT::morx> ();
 
 //   if (0)
 //   {
-//     OT::Sanitizer<AAT::Lookup<OT::GlyphID> >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ());
+//     morx_blob->as<AAT::Lookup<OT::GlyphID> > ()->get_value (1, face->get_num_glyphs ());
 //   }
 // }
 
 void
 hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
 {
+#if 0
   hb_blob_t *blob;
   const AAT::morx& morx = _get_morx (font->face, &blob);
 
   AAT::hb_aat_apply_context_t c (font, buffer, blob);
   morx.apply (&c);
+#endif
 }
 
 void
 hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer)
 {
+#if 0
   hb_blob_t *blob;
   const AAT::ankr& ankr = _get_ankr (font->face, &blob);
   const AAT::kerx& kerx = _get_kerx (font->face, &blob);
   const AAT::trak& trak = _get_trak (font->face, &blob);
 
   AAT::hb_aat_apply_context_t c (font, buffer, blob);
   kerx.apply (&c, &ankr);
   trak.apply (&c);
+#endif
 }
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-aat-ltag-table.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_AAT_LTAG_TABLE_HH
+#define HB_AAT_LTAG_TABLE_HH
+
+#include "hb-aat-layout-common-private.hh"
+
+/*
+ * ltag -- Language Tag
+ * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ltag.html
+ */
+#define HB_AAT_TAG_ltag HB_TAG('l','t','a','g')
+
+
+namespace AAT {
+
+
+struct FTStringRange
+{
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
+  }
+
+  protected:
+  OffsetTo<UnsizedArrayOf<HBUINT8> >
+		tag;		/* Offset from the start of the table to
+				 * the beginning of the string */
+  HBUINT16	length;		/* String length (in bytes) */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct ltag
+{
+  static const hb_tag_t tableTag = HB_AAT_TAG_ltag;
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && tagRanges.sanitize (c, this)));
+  }
+
+  protected:
+  HBUINT32	version;	/* Table version; currently 1 */
+  HBUINT32	flags;		/* Table flags; currently none defined */
+  LArrayOf<FTStringRange>
+		tagRanges;	/* Range for each tag's string */
+  public:
+  DEFINE_SIZE_ARRAY (12, tagRanges);
+};
+
+} /* namespace AAT */
+
+
+#endif /* HB_AAT_LTAG_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-atomic-private.hh
+++ b/gfx/harfbuzz/src/hb-atomic-private.hh
@@ -58,40 +58,37 @@ static inline void _HBMemoryBarrier (voi
   long dummy = 0;
   InterlockedExchange (&dummy, 1);
 #else
   MemoryBarrier ();
 #endif
 }
 
 typedef LONG hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd (&(AI), (V))
 
 #define hb_atomic_ptr_impl_get(P)		(_HBMemoryBarrier (), (void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 typedef int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add (&(AI), (V))
 
 #define hb_atomic_ptr_impl_get(P)		(void *) (__sync_synchronize (), *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
 
 #include <atomic.h>
 #include <mbarrier.h>
 
 typedef unsigned int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
 
 #define hb_atomic_ptr_impl_get(P)		( ({__machine_rw_barrier ();}), (void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
 
 
 #elif !defined(HB_NO_MT) && defined(__APPLE__)
 
@@ -99,17 +96,16 @@ typedef unsigned int hb_atomic_int_impl_
 #ifdef __MAC_OS_X_MIN_REQUIRED
 #include <AvailabilityMacros.h>
 #elif defined(__IPHONE_OS_MIN_REQUIRED)
 #include <Availability.h>
 #endif
 
 
 typedef int32_t hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		(OSAtomicAdd32Barrier ((V), &(AI)) - (V))
 
 #define hb_atomic_ptr_impl_get(P)		(OSMemoryBarrier (), (void *) *(P))
 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
 #else
 #if __ppc64__ || __x86_64__ || __aarch64__
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
@@ -133,48 +129,45 @@ static inline int _hb_fetch_and_add(vola
 static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
   __sync();
   int result = __compare_and_swaplp (P, &O, N);
   __sync();
   return result;
 }
 
 typedef int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)           _hb_fetch_and_add (&(AI), (V))
 
 #define hb_atomic_ptr_impl_get(P)               (__sync(), (void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)       _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
 
 #elif !defined(HB_NO_MT)
 
 #define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
 
 typedef volatile int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
 #define hb_atomic_int_impl_add(AI, V)		(((AI) += (V)) - (V))
 
 #define hb_atomic_ptr_impl_get(P)		((void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
 
 
 #else /* HB_NO_MT */
 
 typedef int hb_atomic_int_impl_t;
-#define HB_ATOMIC_INT_IMPL_INIT(V)		(V)
 #define hb_atomic_int_impl_add(AI, V)		(((AI) += (V)) - (V))
 
 #define hb_atomic_ptr_impl_get(P)		((void *) *(P))
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
 
 #endif
 
 
-#define HB_ATOMIC_INT_INIT(V)		{HB_ATOMIC_INT_IMPL_INIT(V)}
+#define HB_ATOMIC_INT_INIT(V)          {V}
 
 struct hb_atomic_int_t
 {
   hb_atomic_int_impl_t v;
 
   inline void set_unsafe (int v_) { v = v_; }
   inline int get_unsafe (void) const { return v; }
   inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v),  1); }
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-blob-private.hh
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2018  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BLOB_PRIVATE_HH
+#define HB_BLOB_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+
+
+/*
+ * hb_blob_t
+ */
+
+struct hb_blob_t
+{
+  inline void fini_shallow (void)
+  {
+    destroy_user_data ();
+  }
+
+  inline void destroy_user_data (void)
+  {
+    if (destroy)
+    {
+      destroy (user_data);
+      user_data = nullptr;
+      destroy = nullptr;
+    }
+  }
+
+  HB_INTERNAL bool try_make_writable (void);
+  HB_INTERNAL bool try_make_writable_inplace (void);
+  HB_INTERNAL bool try_make_writable_inplace_unix (void);
+
+  inline void lock (void)
+  {
+    hb_blob_make_immutable (this);
+  }
+
+  template <typename Type>
+  inline const Type* as (void) const
+  {
+    return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data);
+  }
+
+  public:
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  bool immutable;
+
+  const char *data;
+  unsigned int length;
+  hb_memory_mode_t mode;
+
+  void *user_data;
+  hb_destroy_func_t destroy;
+};
+
+
+#endif /* HB_BLOB_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-blob.cc
+++ b/gfx/harfbuzz/src/hb-blob.cc
@@ -1,10 +1,11 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -26,56 +27,29 @@
 
 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
 #ifndef _POSIX_C_SOURCE
 #define _POSIX_C_SOURCE 200809L
 #endif
 
 #include "hb-private.hh"
 #include "hb-debug.hh"
-
-#include "hb-object-private.hh"
+#include "hb-blob-private.hh"
 
 #ifdef HAVE_SYS_MMAN_H
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
 #include <sys/mman.h>
 #endif /* HAVE_SYS_MMAN_H */
 
 #include <stdio.h>
 #include <errno.h>
-
-
-struct hb_blob_t {
-  hb_object_header_t header;
-  ASSERT_POD ();
-
-  bool immutable;
-
-  const char *data;
-  unsigned int length;
-  hb_memory_mode_t mode;
+#include <stdlib.h>
 
-  void *user_data;
-  hb_destroy_func_t destroy;
-};
-
-
-static bool _try_writable (hb_blob_t *blob);
-
-static void
-_hb_blob_destroy_user_data (hb_blob_t *blob)
-{
-  if (blob->destroy) {
-    blob->destroy (blob->user_data);
-    blob->user_data = nullptr;
-    blob->destroy = nullptr;
-  }
-}
 
 /**
  * hb_blob_create: (skip)
  * @data: Pointer to blob data.
  * @length: Length of @data in bytes.
  * @mode: Memory mode for @data.
  * @user_data: Data parameter to pass to @destroy.
  * @destroy: Callback to call when @data is not needed anymore.
@@ -109,17 +83,17 @@ hb_blob_create (const char        *data,
   blob->length = length;
   blob->mode = mode;
 
   blob->user_data = user_data;
   blob->destroy = destroy;
 
   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
     blob->mode = HB_MEMORY_MODE_READONLY;
-    if (!_try_writable (blob)) {
+    if (!blob->try_make_writable ()) {
       hb_blob_destroy (blob);
       return hb_blob_get_empty ();
     }
   }
 
   return blob;
 }
 
@@ -255,30 +229,30 @@ hb_blob_reference (hb_blob_t *blob)
  *
  * Since: 0.9.2
  **/
 void
 hb_blob_destroy (hb_blob_t *blob)
 {
   if (!hb_object_destroy (blob)) return;
 
-  _hb_blob_destroy_user_data (blob);
+  blob->fini_shallow ();
 
   free (blob);
 }
 
 /**
  * hb_blob_set_user_data: (skip)
  * @blob: a blob.
  * @key: key for data to set.
  * @data: data to set.
  * @destroy: callback to call when @data is not needed anymore.
  * @replace: whether to replace an existing data with the same key.
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_blob_set_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key,
 		       void *              data,
 		       hb_destroy_func_t   destroy,
@@ -287,88 +261,88 @@ hb_blob_set_user_data (hb_blob_t        
   return hb_object_set_user_data (blob, key, data, destroy, replace);
 }
 
 /**
  * hb_blob_get_user_data: (skip)
  * @blob: a blob.
  * @key: key for data to get.
  *
- * 
+ *
  *
- * Return value: (transfer none): 
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
 void *
 hb_blob_get_user_data (hb_blob_t          *blob,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (blob, key);
 }
 
 
 /**
  * hb_blob_make_immutable:
  * @blob: a blob.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_blob_make_immutable (hb_blob_t *blob)
 {
   if (hb_object_is_inert (blob))
     return;
 
   blob->immutable = true;
 }
 
 /**
  * hb_blob_is_immutable:
  * @blob: a blob.
  *
- * 
+ *
  *
  * Return value: TODO
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_blob_is_immutable (hb_blob_t *blob)
 {
   return blob->immutable;
 }
 
 
 /**
  * hb_blob_get_length:
  * @blob: a blob.
  *
- * 
+ *
  *
  * Return value: the length of blob data in bytes.
  *
  * Since: 0.9.2
  **/
 unsigned int
 hb_blob_get_length (hb_blob_t *blob)
 {
   return blob->length;
 }
 
 /**
  * hb_blob_get_data:
  * @blob: a blob.
  * @length: (out):
  *
- * 
+ *
  *
- * Returns: (transfer none) (array length=length): 
+ * Returns: (transfer none) (array length=length):
  *
  * Since: 0.9.2
  **/
 const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
 {
   if (length)
     *length = blob->length;
@@ -390,115 +364,247 @@ hb_blob_get_data (hb_blob_t *blob, unsig
  * Returns: (transfer none) (array length=length): Writable blob data,
  * or %NULL if failed.
  *
  * Since: 0.9.2
  **/
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
 {
-  if (!_try_writable (blob)) {
+  if (!blob->try_make_writable ()) {
     if (length)
       *length = 0;
 
     return nullptr;
   }
 
   if (length)
     *length = blob->length;
 
   return const_cast<char *> (blob->data);
 }
 
 
-static hb_bool_t
-_try_make_writable_inplace_unix (hb_blob_t *blob)
+bool
+hb_blob_t::try_make_writable_inplace_unix (void)
 {
 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
   uintptr_t pagesize = -1, mask, length;
   const char *addr;
 
 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
   pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
   pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
 #elif defined(HAVE_GETPAGESIZE)
   pagesize = (uintptr_t) getpagesize ();
 #endif
 
   if ((uintptr_t) -1L == pagesize) {
-    DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
+    DEBUG_MSG_FUNC (BLOB, this, "failed to get pagesize: %s", strerror (errno));
     return false;
   }
-  DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
+  DEBUG_MSG_FUNC (BLOB, this, "pagesize is %lu", (unsigned long) pagesize);
 
   mask = ~(pagesize-1);
-  addr = (const char *) (((uintptr_t) blob->data) & mask);
-  length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask)  - addr;
-  DEBUG_MSG_FUNC (BLOB, blob,
+  addr = (const char *) (((uintptr_t) this->data) & mask);
+  length = (const char *) (((uintptr_t) this->data + this->length + pagesize-1) & mask)  - addr;
+  DEBUG_MSG_FUNC (BLOB, this,
 		  "calling mprotect on [%p..%p] (%lu bytes)",
 		  addr, addr+length, (unsigned long) length);
   if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
-    DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
+    DEBUG_MSG_FUNC (BLOB, this, "mprotect failed: %s", strerror (errno));
     return false;
   }
 
-  blob->mode = HB_MEMORY_MODE_WRITABLE;
+  this->mode = HB_MEMORY_MODE_WRITABLE;
 
-  DEBUG_MSG_FUNC (BLOB, blob,
+  DEBUG_MSG_FUNC (BLOB, this,
 		  "successfully made [%p..%p] (%lu bytes) writable\n",
 		  addr, addr+length, (unsigned long) length);
   return true;
 #else
   return false;
 #endif
 }
 
-static bool
-_try_writable_inplace (hb_blob_t *blob)
+bool
+hb_blob_t::try_make_writable_inplace (void)
 {
-  DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
+  DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n");
 
-  if (_try_make_writable_inplace_unix (blob))
+  if (this->try_make_writable_inplace_unix ())
     return true;
 
-  DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
+  DEBUG_MSG_FUNC (BLOB, this, "making writable -> FAILED\n");
 
   /* Failed to make writable inplace, mark that */
-  blob->mode = HB_MEMORY_MODE_READONLY;
+  this->mode = HB_MEMORY_MODE_READONLY;
   return false;
 }
 
-static bool
-_try_writable (hb_blob_t *blob)
+bool
+hb_blob_t::try_make_writable (void)
 {
-  if (blob->immutable)
+  if (this->immutable)
     return false;
 
-  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+  if (this->mode == HB_MEMORY_MODE_WRITABLE)
     return true;
 
-  if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
+  if (this->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && this->try_make_writable_inplace ())
     return true;
 
-  if (blob->mode == HB_MEMORY_MODE_WRITABLE)
+  if (this->mode == HB_MEMORY_MODE_WRITABLE)
     return true;
 
 
-  DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
+  DEBUG_MSG_FUNC (BLOB, this, "current data is -> %p\n", this->data);
 
   char *new_data;
 
-  new_data = (char *) malloc (blob->length);
+  new_data = (char *) malloc (this->length);
   if (unlikely (!new_data))
     return false;
 
-  DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
+  DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
 
-  memcpy (new_data, blob->data, blob->length);
-  _hb_blob_destroy_user_data (blob);
-  blob->mode = HB_MEMORY_MODE_WRITABLE;
-  blob->data = new_data;
-  blob->user_data = new_data;
-  blob->destroy = free;
+  memcpy (new_data, this->data, this->length);
+  this->destroy_user_data ();
+  this->mode = HB_MEMORY_MODE_WRITABLE;
+  this->data = new_data;
+  this->user_data = new_data;
+  this->destroy = free;
 
   return true;
 }
+
+/*
+ * Mmap
+ */
+
+#ifdef HAVE_MMAP
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# include <windows.h>
+#endif
+
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#ifndef MAP_NORESERVE
+# define MAP_NORESERVE 0
+#endif
+
+struct hb_mapped_file_t
+{
+  char *contents;
+  unsigned long length;
+#if defined(_WIN32) || defined(__CYGWIN__)
+  HANDLE mapping;
+#endif
+};
+
+static void
+_hb_mapped_file_destroy (hb_mapped_file_t *file)
+{
+#ifdef HAVE_MMAP
+  munmap (file->contents, file->length);
+#elif defined(_WIN32) || defined(__CYGWIN__)
+  UnmapViewOfFile (file->contents);
+  CloseHandle (file->mapping);
+#else
+  free (file->contents);
+#endif
+
+  free (file);
+}
+
+/**
+ * hb_blob_create_from_file:
+ * @file_name: font filename.
+ *
+ * Returns: A hb_blob_t pointer with the content of the file
+ *
+ * Since: 1.7.7
+ **/
+hb_blob_t *
+hb_blob_create_from_file (const char *file_name)
+{
+  // Adopted from glib's gmappedfile.c with Matthias Clasen and
+  // Allison Lortie permission but changed a lot to suit our need.
+  bool writable = false;
+  hb_memory_mode_t mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  if (unlikely (!file)) return hb_blob_get_empty ();
+
+#ifdef HAVE_MMAP
+  int fd = open (file_name, (writable ? O_RDWR : O_RDONLY) | _O_BINARY, 0);
+# define CLOSE close
+  if (unlikely (fd == -1)) goto fail_without_close;
+
+  struct stat st;
+  if (unlikely (fstat (fd, &st) == -1)) goto fail;
+
+  // See https://github.com/GNOME/glib/blob/f9faac7/glib/gmappedfile.c#L139-L142
+  if (unlikely (st.st_size == 0 && S_ISREG (st.st_mode))) goto fail;
+
+  file->length = (unsigned long) st.st_size;
+  file->contents = (char *) mmap (nullptr, file->length,
+				  writable ? PROT_READ|PROT_WRITE : PROT_READ,
+				  MAP_PRIVATE | MAP_NORESERVE, fd, 0);
+
+  if (unlikely (file->contents == MAP_FAILED)) goto fail;
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
+  HANDLE fd = CreateFile (file_name,
+			  writable ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ,
+			  FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+			  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
+# define CLOSE CloseHandle
+
+  if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
+
+  file->length = (unsigned long) GetFileSize (fd, nullptr);
+  file->mapping = CreateFileMapping (fd, nullptr,
+				     writable ? PAGE_WRITECOPY : PAGE_READONLY,
+				     0, 0, nullptr);
+  if (unlikely (file->mapping == nullptr)) goto fail;
+
+  file->contents = (char *) MapViewOfFile (file->mapping,
+					   writable ? FILE_MAP_COPY : FILE_MAP_READ,
+					   0, 0, 0);
+  if (unlikely (file->contents == nullptr)) goto fail;
+
+#else
+  mm = HB_MEMORY_MODE_WRITABLE;
+
+  FILE *fd = fopen (file_name, "rb");
+# define CLOSE fclose
+  if (unlikely (!fd)) goto fail_without_close;
+
+  fseek (fd, 0, SEEK_END);
+  file->length = ftell (fd);
+  rewind (fd);
+  file->contents = (char *) malloc (file->length);
+  if (unlikely (!file->contents)) goto fail;
+
+  if (unlikely (fread (file->contents, 1, file->length, fd) != file->length))
+    goto fail;
+
+#endif
+
+  CLOSE (fd);
+  return hb_blob_create (file->contents, file->length, mm, (void *) file,
+			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+
+fail:
+  CLOSE (fd);
+#undef CLOSE
+fail_without_close:
+  free (file);
+  return hb_blob_get_empty ();
+}
--- a/gfx/harfbuzz/src/hb-blob.h
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -118,12 +118,14 @@ HB_EXTERN unsigned int
 hb_blob_get_length (hb_blob_t *blob);
 
 HB_EXTERN const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
 
 HB_EXTERN char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_from_file (const char *file_name);
 
 HB_END_DECLS
 
 #endif /* HB_BLOB_H */
--- a/gfx/harfbuzz/src/hb-buffer-deserialize-json.hh
+++ b/gfx/harfbuzz/src/hb-buffer-deserialize-json.hh
@@ -29,407 +29,407 @@
 #ifndef HB_BUFFER_DESERIALIZE_JSON_HH
 #define HB_BUFFER_DESERIALIZE_JSON_HH
 
 #include "hb-private.hh"
 
 
 #line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
-	0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
-	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
-	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
-	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
-	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
+	0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
+	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
+	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
+	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
+	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
 	65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
 };
 
 static const char _deserialize_json_key_spans[] = {
-	0, 115, 26, 7, 2, 1, 50, 49,
-	10, 117, 117, 117, 1, 50, 49, 10,
-	117, 117, 1, 1, 50, 49, 117, 117,
-	2, 1, 50, 49, 10, 117, 117, 1,
-	50, 49, 10, 117, 117, 1, 50, 49,
+	0, 115, 26, 7, 2, 1, 50, 49, 
+	10, 117, 117, 117, 1, 50, 49, 10, 
+	117, 117, 1, 1, 50, 49, 117, 117, 
+	2, 1, 50, 49, 10, 117, 117, 1, 
+	50, 49, 10, 117, 117, 1, 50, 49, 
 	58, 89, 117, 117, 85, 115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
-	0, 0, 116, 143, 151, 154, 156, 207,
-	257, 268, 386, 504, 622, 624, 675, 725,
-	736, 854, 972, 974, 976, 1027, 1077, 1195,
-	1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666,
-	1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069,
+	0, 0, 116, 143, 151, 154, 156, 207, 
+	257, 268, 386, 504, 622, 624, 675, 725, 
+	736, 854, 972, 974, 976, 1027, 1077, 1195, 
+	1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666, 
+	1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069, 
 	2119, 2178, 2268, 2386, 2504, 2590, 2706
 };
 
 static const char _deserialize_json_indicies[] = {
-	0, 0, 0, 0, 0, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 2, 1, 3, 3, 3,
-	3, 3, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 3, 1, 4, 1,
-	5, 1, 6, 7, 1, 1, 8, 1,
-	9, 10, 1, 11, 1, 11, 11, 11,
-	11, 11, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 11, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 12, 1,
-	12, 12, 12, 12, 12, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 12,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 13, 1, 1, 14,
-	15, 15, 15, 15, 15, 15, 15, 15,
-	15, 1, 16, 17, 17, 17, 17, 17,
-	17, 17, 17, 17, 1, 18, 18, 18,
-	18, 18, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 18, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	19, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 20, 1, 21, 21, 21, 21, 21,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 21, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 3, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 22,
-	1, 18, 18, 18, 18, 18, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	18, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 19, 1, 1, 1,
-	17, 17, 17, 17, 17, 17, 17, 17,
-	17, 17, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 20, 1, 23,
-	1, 23, 23, 23, 23, 23, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	23, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 24, 1, 24, 24, 24, 24,
-	24, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 24, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	25, 1, 1, 26, 27, 27, 27, 27,
-	27, 27, 27, 27, 27, 1, 28, 29,
-	29, 29, 29, 29, 29, 29, 29, 29,
-	1, 30, 30, 30, 30, 30, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	30, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 31, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 32, 1, 30,
-	30, 30, 30, 30, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 30, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 31, 1, 1, 1, 29, 29,
-	29, 29, 29, 29, 29, 29, 29, 29,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 32, 1, 33, 1, 34,
-	1, 34, 34, 34, 34, 34, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	34, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 35, 1, 35, 35, 35, 35,
-	35, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 35, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 36, 37, 37, 37, 37,
-	37, 37, 37, 37, 37, 1, 38, 38,
-	38, 38, 38, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 38, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 39, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 40, 1, 38, 38, 38, 38,
-	38, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 38, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 39,
-	1, 1, 1, 41, 41, 41, 41, 41,
-	41, 41, 41, 41, 41, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	40, 1, 42, 43, 1, 44, 1, 44,
-	44, 44, 44, 44, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 44, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	45, 1, 45, 45, 45, 45, 45, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 45, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 46, 1,
-	1, 47, 48, 48, 48, 48, 48, 48,
-	48, 48, 48, 1, 49, 50, 50, 50,
-	50, 50, 50, 50, 50, 50, 1, 51,
-	51, 51, 51, 51, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 51, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 52, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 53, 1, 51, 51, 51,
-	51, 51, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 51, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	52, 1, 1, 1, 50, 50, 50, 50,
-	50, 50, 50, 50, 50, 50, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 53, 1, 54, 1, 54, 54, 54,
-	54, 54, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 54, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 55, 1,
-	55, 55, 55, 55, 55, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 55,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 56, 1, 1, 57,
-	58, 58, 58, 58, 58, 58, 58, 58,
-	58, 1, 59, 60, 60, 60, 60, 60,
-	60, 60, 60, 60, 1, 61, 61, 61,
-	61, 61, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 61, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	62, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 63, 1, 61, 61, 61, 61, 61,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 61, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 62, 1,
-	1, 1, 60, 60, 60, 60, 60, 60,
-	60, 60, 60, 60, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 63,
-	1, 64, 1, 64, 64, 64, 64, 64,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 64, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 65, 1, 65, 65,
-	65, 65, 65, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 65, 1, 66,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 67, 68, 68,
-	68, 68, 68, 68, 68, 68, 68, 1,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 1, 1, 1, 1, 1, 1,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 69, 69, 69, 69, 69, 69,
-	69, 69, 1, 70, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 71, 71,
-	1, 71, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 1, 1, 1, 1, 1,
-	1, 1, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 1, 1, 1, 1,
-	71, 1, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 71, 71, 71, 71,
-	71, 71, 71, 71, 1, 72, 72, 72,
-	72, 72, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 72, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	73, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 74, 1, 72, 72, 72, 72, 72,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 72, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 73, 1,
-	1, 1, 75, 75, 75, 75, 75, 75,
-	75, 75, 75, 75, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 74,
-	1, 76, 76, 76, 76, 76, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	76, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 77, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 78, 1, 0,
-	0, 0, 0, 0, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 0, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 2, 1, 3, 3, 3, 
+	3, 3, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 3, 1, 4, 1, 
+	5, 1, 6, 7, 1, 1, 8, 1, 
+	9, 10, 1, 11, 1, 11, 11, 11, 
+	11, 11, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 11, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 12, 1, 
+	12, 12, 12, 12, 12, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 12, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 13, 1, 1, 14, 
+	15, 15, 15, 15, 15, 15, 15, 15, 
+	15, 1, 16, 17, 17, 17, 17, 17, 
+	17, 17, 17, 17, 1, 18, 18, 18, 
+	18, 18, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 18, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	19, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 20, 1, 21, 21, 21, 21, 21, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 21, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 3, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 22, 
+	1, 18, 18, 18, 18, 18, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	18, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 19, 1, 1, 1, 
+	17, 17, 17, 17, 17, 17, 17, 17, 
+	17, 17, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 20, 1, 23, 
+	1, 23, 23, 23, 23, 23, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	23, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 24, 1, 24, 24, 24, 24, 
+	24, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 24, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	25, 1, 1, 26, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 1, 28, 29, 
+	29, 29, 29, 29, 29, 29, 29, 29, 
+	1, 30, 30, 30, 30, 30, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	30, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 31, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 32, 1, 30, 
+	30, 30, 30, 30, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 30, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 31, 1, 1, 1, 29, 29, 
+	29, 29, 29, 29, 29, 29, 29, 29, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 32, 1, 33, 1, 34, 
+	1, 34, 34, 34, 34, 34, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	34, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 35, 1, 35, 35, 35, 35, 
+	35, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 35, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 36, 37, 37, 37, 37, 
+	37, 37, 37, 37, 37, 1, 38, 38, 
+	38, 38, 38, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 38, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 39, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 40, 1, 38, 38, 38, 38, 
+	38, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 38, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 39, 
+	1, 1, 1, 41, 41, 41, 41, 41, 
+	41, 41, 41, 41, 41, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	40, 1, 42, 43, 1, 44, 1, 44, 
+	44, 44, 44, 44, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 44, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	45, 1, 45, 45, 45, 45, 45, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 45, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 46, 1, 
+	1, 47, 48, 48, 48, 48, 48, 48, 
+	48, 48, 48, 1, 49, 50, 50, 50, 
+	50, 50, 50, 50, 50, 50, 1, 51, 
+	51, 51, 51, 51, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 51, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 52, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 53, 1, 51, 51, 51, 
+	51, 51, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 51, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	52, 1, 1, 1, 50, 50, 50, 50, 
+	50, 50, 50, 50, 50, 50, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 53, 1, 54, 1, 54, 54, 54, 
+	54, 54, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 54, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 55, 1, 
+	55, 55, 55, 55, 55, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 55, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 56, 1, 1, 57, 
+	58, 58, 58, 58, 58, 58, 58, 58, 
+	58, 1, 59, 60, 60, 60, 60, 60, 
+	60, 60, 60, 60, 1, 61, 61, 61, 
+	61, 61, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 61, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	62, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 63, 1, 61, 61, 61, 61, 61, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 61, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 62, 1, 
+	1, 1, 60, 60, 60, 60, 60, 60, 
+	60, 60, 60, 60, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 63, 
+	1, 64, 1, 64, 64, 64, 64, 64, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 64, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 65, 1, 65, 65, 
+	65, 65, 65, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 65, 1, 66, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 67, 68, 68, 
+	68, 68, 68, 68, 68, 68, 68, 1, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 1, 1, 1, 1, 1, 1, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 69, 69, 69, 69, 69, 69, 
+	69, 69, 1, 70, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 71, 71, 
+	1, 71, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 1, 1, 1, 1, 1, 
+	1, 1, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 1, 1, 1, 1, 
+	71, 1, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 71, 71, 71, 71, 
+	71, 71, 71, 71, 1, 72, 72, 72, 
+	72, 72, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 72, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	73, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 74, 1, 72, 72, 72, 72, 72, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 72, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 73, 1, 
+	1, 1, 75, 75, 75, 75, 75, 75, 
+	75, 75, 75, 75, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 74, 
+	1, 76, 76, 76, 76, 76, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	76, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 77, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 78, 1, 0, 
+	0, 0, 0, 0, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 0, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 2, 1, 1, 0
 };
 
 static const char _deserialize_json_trans_targs[] = {
-	1, 0, 2, 2, 3, 4, 18, 24,
-	37, 5, 12, 6, 7, 8, 9, 11,
-	9, 11, 10, 2, 44, 10, 44, 13,
-	14, 15, 16, 17, 16, 17, 10, 2,
-	44, 19, 20, 21, 22, 23, 10, 2,
-	44, 23, 25, 31, 26, 27, 28, 29,
-	30, 29, 30, 10, 2, 44, 32, 33,
-	34, 35, 36, 35, 36, 10, 2, 44,
-	38, 39, 40, 42, 43, 41, 10, 41,
+	1, 0, 2, 2, 3, 4, 18, 24, 
+	37, 5, 12, 6, 7, 8, 9, 11, 
+	9, 11, 10, 2, 44, 10, 44, 13, 
+	14, 15, 16, 17, 16, 17, 10, 2, 
+	44, 19, 20, 21, 22, 23, 10, 2, 
+	44, 23, 25, 31, 26, 27, 28, 29, 
+	30, 29, 30, 10, 2, 44, 32, 33, 
+	34, 35, 36, 35, 36, 10, 2, 44, 
+	38, 39, 40, 42, 43, 41, 10, 41, 
 	10, 2, 44, 43, 44, 45, 46
 };
 
 static const char _deserialize_json_trans_actions[] = {
-	0, 0, 1, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 2, 2, 2,
-	0, 0, 3, 3, 4, 0, 5, 0,
-	0, 2, 2, 2, 0, 0, 6, 6,
-	7, 0, 0, 0, 2, 2, 8, 8,
-	9, 0, 0, 0, 0, 0, 2, 2,
-	2, 0, 0, 10, 10, 11, 0, 0,
-	2, 2, 2, 0, 0, 12, 12, 13,
-	0, 0, 0, 2, 2, 2, 14, 0,
+	0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 2, 2, 2, 
+	0, 0, 3, 3, 4, 0, 5, 0, 
+	0, 2, 2, 2, 0, 0, 6, 6, 
+	7, 0, 0, 0, 2, 2, 8, 8, 
+	9, 0, 0, 0, 0, 0, 2, 2, 
+	2, 0, 0, 10, 10, 11, 0, 0, 
+	2, 2, 2, 0, 0, 12, 12, 13, 
+	0, 0, 0, 2, 2, 2, 14, 0, 
 	15, 15, 16, 0, 0, 0, 0
 };
 
 static const int deserialize_json_start = 1;
 static const int deserialize_json_first_final = 44;
 static const int deserialize_json_error = 0;
 
 static const int deserialize_json_en_main = 1;
@@ -456,17 +456,17 @@ static hb_bool_t
   {
     *end_ptr = ++p;
   }
 
   const char *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
-
+  
 #line 466 "hb-buffer-deserialize-json.hh"
 	{
 	cs = deserialize_json_start;
 	}
 
 #line 471 "hb-buffer-deserialize-json.hh"
 	{
 	int _slen;
@@ -498,17 +498,17 @@ static hb_bool_t
 	memset (&info, 0, sizeof (info));
 	memset (&pos , 0, sizeof (pos ));
 }
 	break;
 	case 5:
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 2:
 #line 51 "hb-buffer-deserialize-json.rl"
 	{
@@ -549,77 +549,77 @@ static hb_bool_t
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 	break;
 	case 16:
 #line 62 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 9:
 #line 63 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 11:
 #line 64 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 13:
 #line 65 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 4:
 #line 66 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 7:
 #line 67 "hb-buffer-deserialize-json.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 #line 624 "hb-buffer-deserialize-json.hh"
 	}
 
--- a/gfx/harfbuzz/src/hb-buffer-deserialize-json.rl
+++ b/gfx/harfbuzz/src/hb-buffer-deserialize-json.rl
@@ -37,17 +37,17 @@ write data;
 
 action clear_item {
 	memset (&info, 0, sizeof (info));
 	memset (&pos , 0, sizeof (pos ));
 }
 
 action add_item {
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 
 action tok {
 	tok = p;
 }
--- a/gfx/harfbuzz/src/hb-buffer-deserialize-text.hh
+++ b/gfx/harfbuzz/src/hb-buffer-deserialize-text.hh
@@ -29,284 +29,284 @@
 #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
 #define HB_BUFFER_DESERIALIZE_TEXT_HH
 
 #include "hb-private.hh"
 
 
 #line 36 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
-	0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
-	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u,
-	9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
+	0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
+	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 
+	9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
 	9u, 124u, 9u, 124u, 9u, 124u, 0
 };
 
 static const char _deserialize_text_key_spans[] = {
-	0, 114, 13, 10, 13, 10, 10, 13,
-	10, 1, 13, 10, 14, 116, 116, 0,
-	114, 116, 116, 116, 116, 116, 116, 116,
+	0, 114, 13, 10, 13, 10, 10, 13, 
+	10, 1, 13, 10, 14, 116, 116, 0, 
+	114, 116, 116, 116, 116, 116, 116, 116, 
 	116, 116, 116
 };
 
 static const short _deserialize_text_index_offsets[] = {
-	0, 0, 115, 129, 140, 154, 165, 176,
-	190, 201, 203, 217, 228, 243, 360, 477,
-	478, 593, 710, 827, 944, 1061, 1178, 1295,
+	0, 0, 115, 129, 140, 154, 165, 176, 
+	190, 201, 203, 217, 228, 243, 360, 477, 
+	478, 593, 710, 827, 944, 1061, 1178, 1295, 
 	1412, 1529, 1646
 };
 
 static const char _deserialize_text_indicies[] = {
-	0, 0, 0, 0, 0, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	2, 3, 3, 3, 3, 3, 3, 3,
-	3, 3, 1, 1, 1, 1, 1, 1,
-	1, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 1, 1, 1, 1, 1,
-	1, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 1, 5, 1, 1, 6,
-	7, 7, 7, 7, 7, 7, 7, 7,
-	7, 1, 8, 9, 9, 9, 9, 9,
-	9, 9, 9, 9, 1, 10, 1, 1,
-	11, 12, 12, 12, 12, 12, 12, 12,
-	12, 12, 1, 13, 14, 14, 14, 14,
-	14, 14, 14, 14, 14, 1, 15, 16,
-	16, 16, 16, 16, 16, 16, 16, 16,
-	1, 17, 1, 1, 18, 19, 19, 19,
-	19, 19, 19, 19, 19, 19, 1, 20,
-	21, 21, 21, 21, 21, 21, 21, 21,
-	21, 1, 22, 1, 23, 1, 1, 24,
-	25, 25, 25, 25, 25, 25, 25, 25,
-	25, 1, 26, 27, 27, 27, 27, 27,
-	27, 27, 27, 27, 1, 22, 1, 1,
-	1, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 1, 28, 28, 28, 28,
-	28, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 28, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 29, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	30, 1, 1, 31, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	32, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 33,
-	1, 34, 34, 34, 34, 34, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	34, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 35, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 36, 1, 1, 0,
-	0, 0, 0, 0, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 0, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 2, 3,
-	3, 3, 3, 3, 3, 3, 3, 3,
-	1, 1, 1, 1, 1, 1, 1, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 1, 1, 1, 1, 1, 1, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 4, 4, 4, 4, 4, 4, 4,
-	4, 1, 28, 28, 28, 28, 28, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 28, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 29, 1, 1, 1,
-	1, 37, 37, 37, 37, 37, 37, 37,
-	37, 37, 37, 1, 1, 1, 30, 1,
-	1, 31, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 32, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 33, 1, 38,
-	38, 38, 38, 38, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 38, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 39, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 40, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 41, 1, 42, 42, 42, 42,
-	42, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 42, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	43, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 44,
-	1, 42, 42, 42, 42, 42, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	42, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	14, 14, 14, 14, 14, 14, 14, 14,
-	14, 14, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 43, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 44, 1, 38, 38,
-	38, 38, 38, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 38, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 39, 1, 1, 1, 9, 9, 9,
-	9, 9, 9, 9, 9, 9, 9, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 40, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 41, 1, 45, 45, 45, 45, 45,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 45, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 46, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 47, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 48,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 49, 1,
-	50, 50, 50, 50, 50, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 50,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 51, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 52, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 53, 1, 50, 50, 50,
-	50, 50, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 50, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 51,
-	1, 1, 1, 1, 27, 27, 27, 27,
-	27, 27, 27, 27, 27, 27, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 52, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	53, 1, 45, 45, 45, 45, 45, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 45, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 46, 1, 1, 1,
-	1, 54, 54, 54, 54, 54, 54, 54,
-	54, 54, 54, 1, 1, 1, 1, 1,
-	1, 47, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 48, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 49, 1, 28,
-	28, 28, 28, 28, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 28, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 29, 1, 55, 55, 1, 55, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	1, 1, 1, 30, 1, 1, 31, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	55, 1, 1, 32, 1, 55, 1, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
-	55, 55, 55, 55, 55, 55, 55, 55,
+	0, 0, 0, 0, 0, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	2, 3, 3, 3, 3, 3, 3, 3, 
+	3, 3, 1, 1, 1, 1, 1, 1, 
+	1, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 1, 1, 1, 1, 1, 
+	1, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 1, 5, 1, 1, 6, 
+	7, 7, 7, 7, 7, 7, 7, 7, 
+	7, 1, 8, 9, 9, 9, 9, 9, 
+	9, 9, 9, 9, 1, 10, 1, 1, 
+	11, 12, 12, 12, 12, 12, 12, 12, 
+	12, 12, 1, 13, 14, 14, 14, 14, 
+	14, 14, 14, 14, 14, 1, 15, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	1, 17, 1, 1, 18, 19, 19, 19, 
+	19, 19, 19, 19, 19, 19, 1, 20, 
+	21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 1, 22, 1, 23, 1, 1, 24, 
+	25, 25, 25, 25, 25, 25, 25, 25, 
+	25, 1, 26, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 1, 22, 1, 1, 
+	1, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 1, 28, 28, 28, 28, 
+	28, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 28, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 29, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	30, 1, 1, 31, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	32, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 33, 
+	1, 34, 34, 34, 34, 34, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	34, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 35, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 36, 1, 1, 0, 
+	0, 0, 0, 0, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 0, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 2, 3, 
+	3, 3, 3, 3, 3, 3, 3, 3, 
+	1, 1, 1, 1, 1, 1, 1, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 1, 1, 1, 1, 1, 1, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 4, 4, 
+	4, 1, 28, 28, 28, 28, 28, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 28, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 29, 1, 1, 1, 
+	1, 37, 37, 37, 37, 37, 37, 37, 
+	37, 37, 37, 1, 1, 1, 30, 1, 
+	1, 31, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 32, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 33, 1, 38, 
+	38, 38, 38, 38, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 38, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 39, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 40, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 41, 1, 42, 42, 42, 42, 
+	42, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 42, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	43, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 44, 
+	1, 42, 42, 42, 42, 42, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	42, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	14, 14, 14, 14, 14, 14, 14, 14, 
+	14, 14, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 43, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 44, 1, 38, 38, 
+	38, 38, 38, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 38, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 39, 1, 1, 1, 9, 9, 9, 
+	9, 9, 9, 9, 9, 9, 9, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 40, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 41, 1, 45, 45, 45, 45, 45, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 45, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 46, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 47, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 48, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 49, 1, 
+	50, 50, 50, 50, 50, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 50, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 51, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 52, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 53, 1, 50, 50, 50, 
+	50, 50, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 50, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 51, 
+	1, 1, 1, 1, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 52, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	53, 1, 45, 45, 45, 45, 45, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 45, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 46, 1, 1, 1, 
+	1, 54, 54, 54, 54, 54, 54, 54, 
+	54, 54, 54, 1, 1, 1, 1, 1, 
+	1, 47, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 48, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 49, 1, 28, 
+	28, 28, 28, 28, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 28, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 29, 1, 55, 55, 1, 55, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	1, 1, 1, 30, 1, 1, 31, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 1, 1, 32, 1, 55, 1, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
 	55, 1, 33, 1, 0
 };
 
 static const char _deserialize_text_trans_targs[] = {
-	1, 0, 13, 17, 26, 3, 18, 21,
-	18, 21, 5, 19, 20, 19, 20, 22,
-	25, 8, 9, 12, 9, 12, 10, 11,
-	23, 24, 23, 24, 14, 2, 6, 7,
-	15, 16, 14, 15, 16, 17, 14, 4,
-	15, 16, 14, 15, 16, 14, 2, 7,
+	1, 0, 13, 17, 26, 3, 18, 21, 
+	18, 21, 5, 19, 20, 19, 20, 22, 
+	25, 8, 9, 12, 9, 12, 10, 11, 
+	23, 24, 23, 24, 14, 2, 6, 7, 
+	15, 16, 14, 15, 16, 17, 14, 4, 
+	15, 16, 14, 15, 16, 14, 2, 7, 
 	15, 16, 14, 2, 15, 16, 25, 26
 };
 
 static const char _deserialize_text_trans_actions[] = {
-	0, 0, 1, 1, 1, 2, 2, 2,
-	0, 0, 2, 2, 2, 0, 0, 2,
-	2, 2, 2, 2, 0, 0, 3, 2,
-	2, 2, 0, 0, 4, 5, 5, 5,
-	4, 4, 0, 0, 0, 0, 6, 7,
-	6, 6, 8, 8, 8, 9, 10, 10,
+	0, 0, 1, 1, 1, 2, 2, 2, 
+	0, 0, 2, 2, 2, 0, 0, 2, 
+	2, 2, 2, 2, 0, 0, 3, 2, 
+	2, 2, 0, 0, 4, 5, 5, 5, 
+	4, 4, 0, 0, 0, 0, 6, 7, 
+	6, 6, 8, 8, 8, 9, 10, 10, 
 	9, 9, 11, 12, 11, 11, 0, 0
 };
 
 static const char _deserialize_text_eof_actions[] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 4, 0, 0,
-	0, 4, 6, 8, 8, 6, 9, 11,
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 4, 0, 0, 
+	0, 4, 6, 8, 8, 6, 9, 11, 
 	11, 9, 4
 };
 
 static const int deserialize_text_start = 1;
 static const int deserialize_text_first_final = 13;
 static const int deserialize_text_error = 0;
 
 static const int deserialize_text_en_main = 1;
@@ -333,17 +333,17 @@ static hb_bool_t
   {
     *end_ptr = ++p;
   }
 
   const char *eof = pe, *tok = nullptr;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
-
+  
 #line 343 "hb-buffer-deserialize-text.hh"
 	{
 	cs = deserialize_text_start;
 	}
 
 #line 348 "hb-buffer-deserialize-text.hh"
 	{
 	int _slen;
@@ -417,65 +417,65 @@ static hb_bool_t
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
 }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 9:
 #line 62 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 11:
 #line 64 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 6:
 #line 65 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 8:
 #line 66 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 #line 480 "hb-buffer-deserialize-text.hh"
 	}
 
@@ -494,65 +494,65 @@ static hb_bool_t
 	if (!hb_font_glyph_from_string (font,
 					tok, p - tok,
 					&info.codepoint))
 	  return false;
 }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 9:
 #line 62 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 11:
 #line 64 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 6:
 #line 65 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 	case 8:
 #line 66 "hb-buffer-deserialize-text.rl"
 	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-text.rl"
 	{
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 	break;
 #line 557 "hb-buffer-deserialize-text.hh"
 	}
 	}
--- a/gfx/harfbuzz/src/hb-buffer-deserialize-text.rl
+++ b/gfx/harfbuzz/src/hb-buffer-deserialize-text.rl
@@ -37,17 +37,17 @@ write data;
 
 action clear_item {
 	memset (&info, 0, sizeof (info));
 	memset (&pos , 0, sizeof (pos ));
 }
 
 action add_item {
 	buffer->add_info (info);
-	if (buffer->in_error)
+	if (unlikely (!buffer->successful))
 	  return false;
 	buffer->pos[buffer->len - 1] = pos;
 	*end_ptr = p;
 }
 
 action tok {
 	tok = p;
 }
--- a/gfx/harfbuzz/src/hb-buffer-private.hh
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -96,17 +96,17 @@ struct hb_buffer_t {
   hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
   unsigned int max_len; /* Maximum allowed len. */
   int max_ops; /* Maximum allowed operations. */
 
   /* Buffer contents */
   hb_buffer_content_type_t content_type;
   hb_segment_properties_t props; /* Script, language, direction */
 
-  bool in_error; /* Allocation failed */
+  bool successful; /* Allocations successful */
   bool have_output; /* Whether we have an output buffer going on */
   bool have_positions; /* Whether we have positions */
 
   unsigned int idx; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
   unsigned int out_len; /* Length of ->out array if have_output */
 
   unsigned int allocated; /* Length of allocated arrays */
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -106,21 +106,21 @@ hb_segment_properties_hash (const hb_seg
 
 
 
 /* Internal API */
 
 bool
 hb_buffer_t::enlarge (unsigned int size)
 {
-  if (unlikely (in_error))
+  if (unlikely (!successful))
     return false;
   if (unlikely (size > max_len))
   {
-    in_error = true;
+    successful = false;
     return false;
   }
 
   unsigned int new_allocated = allocated;
   hb_glyph_position_t *new_pos = nullptr;
   hb_glyph_info_t *new_info = nullptr;
   bool separate_out = out_info != info;
 
@@ -134,29 +134,29 @@ hb_buffer_t::enlarge (unsigned int size)
   if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
   new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
   new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
 
 done:
   if (unlikely (!new_pos || !new_info))
-    in_error = true;
+    successful = false;
 
   if (likely (new_pos))
     pos = new_pos;
 
   if (likely (new_info))
     info = new_info;
 
   out_info = separate_out ? (hb_glyph_info_t *) pos : info;
-  if (likely (!in_error))
+  if (likely (successful))
     allocated = new_allocated;
 
-  return likely (!in_error);
+  return likely (successful);
 }
 
 bool
 hb_buffer_t::make_room_for (unsigned int num_in,
 			    unsigned int num_out)
 {
   if (unlikely (!ensure (out_len + num_out))) return false;
 
@@ -229,17 +229,17 @@ hb_buffer_t::clear (void)
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
   scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
 
   content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
-  in_error = false;
+  successful = true;
   have_output = false;
   have_positions = false;
 
   idx = 0;
   len = 0;
   out_len = 0;
   out_info = info;
 
@@ -319,17 +319,17 @@ hb_buffer_t::clear_positions (void)
   out_info = info;
 
   memset (pos, 0, sizeof (pos[0]) * len);
 }
 
 void
 hb_buffer_t::swap_buffers (void)
 {
-  if (unlikely (in_error)) return;
+  if (unlikely (!successful)) return;
 
   assert (have_output);
   have_output = false;
 
   if (out_info != info)
   {
     hb_glyph_info_t *tmp_string;
     tmp_string = info;
@@ -404,17 +404,17 @@ bool
 hb_buffer_t::move_to (unsigned int i)
 {
   if (!have_output)
   {
     assert (i <= len);
     idx = i;
     return true;
   }
-  if (unlikely (in_error))
+  if (unlikely (!successful))
     return false;
 
   assert (i <= out_len + (len - idx));
 
   if (out_len < i)
   {
     unsigned int count = i - out_len;
     if (unlikely (!make_room_for (count, count))) return false;
@@ -682,16 +682,18 @@ hb_buffer_t::guess_segment_properties (v
         break;
       }
     }
   }
 
   /* If direction is set to INVALID, guess from script */
   if (props.direction == HB_DIRECTION_INVALID) {
     props.direction = hb_script_get_horizontal_direction (props.script);
+    if (props.direction == HB_DIRECTION_INVALID)
+      props.direction = HB_DIRECTION_LTR;
   }
 
   /* If language is not set, use default language from locale */
   if (props.language == HB_LANGUAGE_INVALID) {
     /* TODO get_default_for_script? using $LANGUAGE */
     props.language = hb_language_get_default ();
   }
 }
@@ -749,17 +751,17 @@ hb_buffer_get_empty (void)
     HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
     HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
     HB_BUFFER_SCRATCH_FLAG_DEFAULT,
     HB_BUFFER_MAX_LEN_DEFAULT,
     HB_BUFFER_MAX_OPS_DEFAULT,
 
     HB_BUFFER_CONTENT_TYPE_INVALID,
     HB_SEGMENT_PROPERTIES_DEFAULT,
-    true, /* in_error */
+    false, /* successful */
     true, /* have_output */
     true  /* have_positions */
 
     /* Zero is good enough for everything else. */
   };
 
   return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
 }
@@ -1264,17 +1266,17 @@ hb_buffer_pre_allocate (hb_buffer_t *buf
  * Return value:
  * %true if @buffer memory allocation succeeded, %false otherwise.
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
 {
-  return !buffer->in_error;
+  return buffer->successful;
 }
 
 /**
  * hb_buffer_add:
  * @buffer: an #hb_buffer_t.
  * @codepoint: a Unicode code point.
  * @cluster: the cluster value of @codepoint.
  *
@@ -1484,16 +1486,18 @@ hb_buffer_reverse_clusters (hb_buffer_t 
  * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
  * will be set to the Unicode script of the first character in
  * the buffer that has a script other than %HB_SCRIPT_COMMON,
  * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
  *
  * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
  * it will be set to the natural horizontal direction of the
  * buffer script as returned by hb_script_get_horizontal_direction().
+ * If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID,
+ * then %HB_DIRECTION_LTR is used.
  *
  * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
  * it will be set to the process's default language as returned by
  * hb_language_get_default().  This may change in the future by
  * taking buffer script into consideration when choosing a language.
  *
  * Since: 0.9.7
  **/
@@ -1745,23 +1749,23 @@ hb_buffer_append (hb_buffer_t *buffer,
 
   if (!buffer->len)
     buffer->content_type = source->content_type;
   if (!buffer->have_positions && source->have_positions)
     buffer->clear_positions ();
 
   if (buffer->len + (end - start) < buffer->len) /* Overflows. */
   {
-    buffer->in_error = true;
+    buffer->successful = false;
     return;
   }
 
   unsigned int orig_len = buffer->len;
   hb_buffer_set_length (buffer, buffer->len + (end - start));
-  if (buffer->in_error)
+  if (unlikely (!buffer->successful))
     return;
 
   memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
   if (buffer->have_positions)
     memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
 }
 
 
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -55,22 +55,22 @@ void
   _hb_options = u;
 }
 
 
 /* hb_tag_t */
 
 /**
  * hb_tag_from_string:
- * @str: (array length=len) (element-type uint8_t): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_tag_t
 hb_tag_from_string (const char *str, int len)
 {
   char tag[4];
   unsigned int i;
@@ -85,20 +85,20 @@ hb_tag_from_string (const char *str, int
   for (; i < 4; i++)
     tag[i] = ' ';
 
   return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
 }
 
 /**
  * hb_tag_to_string:
- * @tag: 
- * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): 
+ * @tag:
+ * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
  *
- * 
+ *
  *
  * Since: 0.9.5
  **/
 void
 hb_tag_to_string (hb_tag_t tag, char *buf)
 {
   buf[0] = (char) (uint8_t) (tag >> 24);
   buf[1] = (char) (uint8_t) (tag >> 16);
@@ -113,22 +113,22 @@ const char direction_strings[][4] = {
   "ltr",
   "rtl",
   "ttb",
   "btt"
 };
 
 /**
  * hb_direction_from_string:
- * @str: (array length=len) (element-type uint8_t): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_direction_t
 hb_direction_from_string (const char *str, int len)
 {
   if (unlikely (!str || !len || !*str))
     return HB_DIRECTION_INVALID;
@@ -141,21 +141,21 @@ hb_direction_from_string (const char *st
     if (c == direction_strings[i][0])
       return (hb_direction_t) (HB_DIRECTION_LTR + i);
 
   return HB_DIRECTION_INVALID;
 }
 
 /**
  * hb_direction_to_string:
- * @direction: 
+ * @direction:
+ *
  *
- * 
  *
- * Return value: (transfer none): 
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
 const char *
 hb_direction_to_string (hb_direction_t direction)
 {
   if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
 	      < ARRAY_LENGTH (direction_strings)))
@@ -220,48 +220,53 @@ struct hb_language_item_t {
   hb_language_t lang;
 
   inline bool operator == (const char *s) const {
     return lang_equal (lang, s);
   }
 
   inline hb_language_item_t & operator = (const char *s) {
     /* If a custom allocated is used calling strdup() pairs
-    badly with a call to the custom free() in finish() below.
+    badly with a call to the custom free() in fini() below.
     Therefore don't call strdup(), implement its behavior.
     */
     size_t len = strlen(s) + 1;
     lang = (hb_language_t) malloc(len);
     if (likely (lang))
     {
       memcpy((unsigned char *) lang, s, len);
       for (unsigned char *p = (unsigned char *) lang; *p; p++)
 	*p = canon_map[*p];
     }
 
     return *this;
   }
 
-  void finish (void) { free ((void *) lang); }
+  void fini (void) { free ((void *) lang); }
 };
 
 
 /* Thread-safe lock-free language list */
 
 static hb_language_item_t *langs;
 
 #ifdef HB_USE_ATEXIT
 static void
 free_langs (void)
 {
-  while (langs) {
-    hb_language_item_t *next = langs->next;
-    langs->finish ();
-    free (langs);
-    langs = next;
+retry:
+  hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
+  if (!hb_atomic_ptr_cmpexch (&langs, first_lang, nullptr))
+    goto retry;
+
+  while (first_lang) {
+    hb_language_item_t *next = first_lang->next;
+    first_lang->fini ();
+    free (first_lang);
+    first_lang = next;
   }
 }
 #endif
 
 static hb_language_item_t *
 lang_find_or_insert (const char *key)
 {
 retry:
@@ -279,17 +284,17 @@ retry:
   *lang = key;
   if (unlikely (!lang->lang))
   {
     free (lang);
     return nullptr;
   }
 
   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
-    lang->finish ();
+    lang->fini ();
     free (lang);
     goto retry;
   }
 
 #ifdef HB_USE_ATEXIT
   if (!first_lang)
     atexit (free_langs); /* First person registers atexit() callback. */
 #endif
@@ -351,17 +356,17 @@ hb_language_to_string (hb_language_t lan
 {
   /* This is actually nullptr-safe! */
   return language->s;
 }
 
 /**
  * hb_language_get_default:
  *
- * 
+ *
  *
  * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
 hb_language_t
 hb_language_get_default (void)
 {
@@ -380,17 +385,17 @@ hb_language_get_default (void)
 /* hb_script_t */
 
 /**
  * hb_script_from_iso15924_tag:
  * @tag: an #hb_tag_t representing an ISO 15924 tag.
  *
  * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
  *
- * Return value: 
+ * Return value:
  * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag)
 {
   if (unlikely (tag == HB_TAG_NONE))
@@ -402,17 +407,17 @@ hb_script_from_iso15924_tag (hb_tag_t ta
   switch (tag) {
 
     /* These graduated from the 'Q' private-area codes, but
      * the old code is still aliased by Unicode, and the Qaai
      * one in use by ICU. */
     case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
     case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
 
-    /* Script variants from http://unicode.org/iso15924/ */
+    /* Script variants from https://unicode.org/iso15924/ */
     case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
     case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
     case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
     case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
     case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
     case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
   }
 
@@ -429,17 +434,17 @@ hb_script_from_iso15924_tag (hb_tag_t ta
  * @str: (array length=len) (element-type uint8_t): a string representing an
  *       ISO 15924 tag.
  * @len: length of the @str, or -1 if it is %NULL-terminated.
  *
  * Converts a string @str representing an ISO 15924 script tag to a
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
  * hb_script_from_iso15924_tag().
  *
- * Return value: 
+ * Return value:
  * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
  **/
 hb_script_t
 hb_script_from_string (const char *str, int len)
 {
   return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
@@ -459,28 +464,28 @@ hb_script_from_string (const char *str, 
 hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script)
 {
   return (hb_tag_t) script;
 }
 
 /**
  * hb_script_get_horizontal_direction:
- * @script: 
+ * @script:
+ *
  *
- * 
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script)
 {
-  /* http://goo.gl/x9ilM */
+  /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
   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:
@@ -525,17 +530,28 @@ hb_script_get_horizontal_direction (hb_s
 
     /* Unicode-8.0 additions */
     case HB_SCRIPT_HATRAN:
     case HB_SCRIPT_OLD_HUNGARIAN:
 
     /* Unicode-9.0 additions */
     case HB_SCRIPT_ADLAM:
 
+    /* Unicode-11.0 additions */
+    case HB_SCRIPT_HANIFI_ROHINGYA:
+    case HB_SCRIPT_OLD_SOGDIAN:
+    case HB_SCRIPT_SOGDIAN:
+
       return HB_DIRECTION_RTL;
+
+
+    /* https://github.com/harfbuzz/harfbuzz/issues/1000 */
+    case HB_SCRIPT_OLD_ITALIC:
+
+      return HB_DIRECTION_INVALID;
   }
 
   return HB_DIRECTION_LTR;
 }
 
 
 /* hb_user_data_array_t */
 
@@ -603,23 +619,23 @@ hb_version (unsigned int *major,
 const char *
 hb_version_string (void)
 {
   return HB_VERSION_STRING;
 }
 
 /**
  * hb_version_atleast:
- * @major: 
- * @minor: 
- * @micro: 
+ * @major:
+ * @minor:
+ * @micro:
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.30
  **/
 hb_bool_t
 hb_version_atleast (unsigned int major,
 		    unsigned int minor,
 		    unsigned int micro)
 {
@@ -714,18 +730,24 @@ parse_uint32 (const char **pp, const cha
 #ifdef USE_XLOCALE
 
 static HB_LOCALE_T C_locale;
 
 #ifdef HB_USE_ATEXIT
 static void
 free_C_locale (void)
 {
-  if (C_locale)
-    HB_FREE_LOCALE (C_locale);
+retry:
+  HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
+
+  if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr))
+    goto retry;
+
+  if (locale)
+    HB_FREE_LOCALE (locale);
 }
 #endif
 
 static HB_LOCALE_T
 get_C_locale (void)
 {
 retry:
   HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
--- a/gfx/harfbuzz/src/hb-common.h
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -44,16 +44,26 @@
 #endif
 
 #if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
     defined (_sgi) || defined (__sun) || defined (sun) || \
     defined (__digital__) || defined (__HP_cc)
 #  include <inttypes.h>
 #elif defined (_AIX)
 #  include <sys/inttypes.h>
+#elif defined (_MSC_VER) && _MSC_VER < 1600
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
 #else
 #  include <stdint.h>
 #endif
 
 HB_BEGIN_DECLS
 
 
 typedef int hb_bool_t;
@@ -137,18 +147,18 @@ hb_language_to_string (hb_language_t lan
 #define HB_LANGUAGE_INVALID ((hb_language_t) 0)
 
 HB_EXTERN hb_language_t
 hb_language_get_default (void);
 
 
 /* hb_script_t */
 
-/* http://unicode.org/iso15924/ */
-/* http://goo.gl/x9ilM */
+/* https://unicode.org/iso15924/ */
+/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
 /* Unicode Character Database property: Script (sc) */
 typedef enum
 {
   /*1.1*/ HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
   /*1.1*/ HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
   /*5.0*/ HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),
 
   /*1.1*/ HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
@@ -310,25 +320,36 @@ typedef enum
   /*
    * Since 1.6.0
    */
   /*10.0*/HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'),
   /*10.0*/HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'),
   /*10.0*/HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'),
   /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'),
 
+  /*
+   * Since 1.8.0
+   */
+  /*11.0*/HB_SCRIPT_DOGRA			= HB_TAG ('D','o','g','r'),
+  /*11.0*/HB_SCRIPT_GUNJALA_GONDI		= HB_TAG ('G','o','n','g'),
+  /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA		= HB_TAG ('R','o','h','g'),
+  /*11.0*/HB_SCRIPT_MAKASAR			= HB_TAG ('M','a','k','a'),
+  /*11.0*/HB_SCRIPT_MEDEFAIDRIN			= HB_TAG ('M','e','d','f'),
+  /*11.0*/HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'),
+  /*11.0*/HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'),
+
   /* No script set. */
   HB_SCRIPT_INVALID				= HB_TAG_NONE,
 
   /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
    * without risking undefined behavior.  Include both a signed and unsigned max,
    * since technically enums are int, and indeed, hb_script_t ends up being signed.
    * See this thread for technicalities:
    *
-   *   http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
+   *   https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
    */
   _HB_SCRIPT_MAX_VALUE				= HB_TAG_MAX, /*< skip >*/
   _HB_SCRIPT_MAX_VALUE_SIGNED			= HB_TAG_MAX_SIGNED /*< skip >*/
 
 } hb_script_t;
 
 
 /* Script functions */
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -163,16 +163,20 @@ create_ct_font (CGFontRef cg_font, CGFlo
 
   /* CoreText does not enable trak table usage / tracking when creating a CTFont
    * using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
    * to be through the CTFontCreateUIFontForLanguage call. */
   CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
   if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
       CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
   {
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
+# define kCTFontUIFontSystem kCTFontSystemFontType
+# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
+#endif
     CTFontUIFontType font_type = kCTFontUIFontSystem;
     if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
       font_type = kCTFontUIFontEmphasizedSystem;
 
     ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
     CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
     if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
     {
@@ -201,17 +205,28 @@ create_ct_font (CGFontRef cg_font, CGFlo
   if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
     CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
     bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
     CFRelease (fontName);
     if (!isEmojiFont)
       return ct_font;
   }
 
-  CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
+  CFURLRef original_url = nullptr;
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+  ATSFontRef atsFont;
+  FSRef fsref;
+  OSStatus status;
+  atsFont = CTFontGetPlatformFont (ct_font, NULL);
+  status = ATSFontGetFileReference (atsFont, &fsref);
+  if (status == noErr)
+    original_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+  original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
+#endif
 
   /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
    * font fallback which we don't need anyway. */
   {
     CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
     CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
     CFRelease (last_resort_font_desc);
     if (new_ct_font)
@@ -220,17 +235,25 @@ create_ct_font (CGFontRef cg_font, CGFlo
        * when reconfiguring the cascade list and may switch to a different font
        * when there are fonts that go by the same name, since the descriptor is
        * just name and size.
        *
        * Avoid reconfiguring the cascade lists if the new font is outside the
        * system locations that we cannot access from the sandboxed renderer
        * process in Blink. This can be detected by the new file URL location
        * that the newly found font points to. */
-      CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+      CFURLRef new_url = nullptr;
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+      atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
+      status = ATSFontGetFileReference (atsFont, &fsref);
+      if (status == noErr)
+        new_url = CFURLCreateFromFSRef (NULL, &fsref);
+#else
+      new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+#endif
       // Keep reconfigured font if URL cannot be retrieved (seems to be the case
       // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
       if (!original_url || !new_url || CFEqual (original_url, new_url)) {
         CFRelease (ct_font);
         ct_font = new_ct_font;
       } else {
         CFRelease (new_ct_font);
         DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
@@ -613,27 +636,27 @@ hb_bool_t
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
     hb_glyph_info_t *info = buffer->info;
     for (unsigned int i = 1; i < count; i++)
       if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
 	buffer->merge_clusters (i - 1, i + 1);
   }
 
-  hb_auto_array_t<feature_record_t> feature_records;
-  hb_auto_array_t<range_record_t> range_records;
+  hb_auto_t<hb_vector_t<feature_record_t> > feature_records;
+  hb_auto_t<hb_vector_t<range_record_t> > range_records;
 
   /*
    * Set up features.
    * (copied + modified from code from hb-uniscribe.cc)
    */
   if (num_features)
   {
     /* Sort features by start/end events. */
-    hb_auto_array_t<feature_event_t> feature_events;
+    hb_auto_t<hb_vector_t<feature_event_t> > feature_events;
     for (unsigned int i = 0; i < num_features; i++)
     {
       const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
 									       feature_mappings,
 									       ARRAY_LENGTH (feature_mappings),
 									       sizeof (feature_mappings[0]),
 									       _hb_feature_mapping_cmp);
       if (!mapping)
@@ -642,58 +665,50 @@ hb_bool_t
       active_feature_t feature;
       feature.rec.feature = mapping->aatFeatureType;
       feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
       feature.order = i;
 
       feature_event_t *event;
 
       event = feature_events.push ();
-      if (unlikely (!event))
-	goto fail_features;
       event->index = features[i].start;
       event->start = true;
       event->feature = feature;
 
       event = feature_events.push ();
-      if (unlikely (!event))
-	goto fail_features;
       event->index = features[i].end;
       event->start = false;
       event->feature = feature;
     }
     feature_events.qsort ();
     /* Add a strategic final event. */
     {
       active_feature_t feature;
       feature.rec.feature = HB_TAG_NONE;
       feature.rec.setting = 0;
       feature.order = num_features + 1;
 
       feature_event_t *event = feature_events.push ();
-      if (unlikely (!event))
-	goto fail_features;
       event->index = 0; /* This value does magic. */
       event->start = false;
       event->feature = feature;
     }
 
     /* Scan events and save features for each range. */
-    hb_auto_array_t<active_feature_t> active_features;
+    hb_auto_t<hb_vector_t<active_feature_t> > active_features;
     unsigned int last_index = 0;
     for (unsigned int i = 0; i < feature_events.len; i++)
     {
       feature_event_t *event = &feature_events[i];
 
       if (event->index != last_index)
       {
         /* Save a snapshot of active features and the range. */
 	range_record_t *range = range_records.push ();
-	if (unlikely (!range))
-	  goto fail_features;
 
 	if (active_features.len)
 	{
 	  CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 
 	  /* TODO sort and resolve conflicting features? */
 	  /* active_features.qsort (); */
 	  for (unsigned int j = 0; j < active_features.len; j++)
@@ -741,33 +756,26 @@ hb_bool_t
 	}
 
 	range->index_first = last_index;
 	range->index_last  = event->index - 1;
 
 	last_index = event->index;
       }
 
-      if (event->start) {
-        active_feature_t *feature = active_features.push ();
-	if (unlikely (!feature))
-	  goto fail_features;
-	*feature = event->feature;
+      if (event->start)
+      {
+        active_features.push (event->feature);
       } else {
         active_feature_t *feature = active_features.find (&event->feature);
 	if (feature)
-	  active_features.remove (feature - active_features.array);
+	  active_features.remove (feature - active_features.arrayZ);
       }
     }
   }
-  else
-  {
-  fail_features:
-    num_features = 0;
-  }
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 
 #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
   Type *name = (Type *) scratch; \
   { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
@@ -939,16 +947,19 @@ resize_and_retry:
 	      CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
 	  }
 	}
 	CFRelease (zero);
       }
 
       int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
       CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+      extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
+#endif
       CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
 						    (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
 						    (const void **) &level_number,
 						    1,
 						    &kCFTypeDictionaryKeyCallBacks,
 						    &kCFTypeDictionaryValueCallBacks);
       CFRelease (level_number);
       if (unlikely (!options))
@@ -974,17 +985,17 @@ resize_and_retry:
     DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
 
     buffer->len = 0;
     uint32_t status_and = ~0, status_or = 0;
     double advances_so_far = 0;
     /* For right-to-left runs, CoreText returns the glyphs positioned such that
      * any trailing whitespace is to the left of (0,0).  Adjust coordinate system
      * to fix for that.  Test with any RTL string with trailing spaces.
-     * https://code.google.com/p/chromium/issues/detail?id=469028
+     * https://crbug.com/469028
      */
     if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
     {
       advances_so_far -= CTLineGetTrailingWhitespaceWidth (line);
       if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
 	  advances_so_far = -advances_so_far;
     }
 
@@ -1027,17 +1038,17 @@ resize_and_retry:
 	 *
 	 * Looks like if we really want to be sure here we have to modify the
 	 * font to change the name table, similar to what we do in the uniscribe
 	 * backend.
 	 *
 	 * However, even that wouldn't work if we were passed in the CGFont to
 	 * construct a hb_face to begin with.
 	 *
-	 * See: http://github.com/harfbuzz/harfbuzz/pull/36
+	 * See: https://github.com/harfbuzz/harfbuzz/pull/36
 	 *
 	 * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
 	 */
 	bool matched = false;
 	for (unsigned int i = 0; i < range_records.len; i++)
 	  if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
 	  {
 	    matched = true;
@@ -1217,17 +1228,17 @@ resize_and_retry:
       buffer->len += num_glyphs;
     }
 
     /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
      * or if it does, it doesn't respect it.  So we get runs with wrong
      * directions.  As such, disable the assert...  It wouldn't crash, but
      * cursoring will be off...
      *
-     * http://crbug.com/419769
+     * https://crbug.com/419769
      */
     if (0)
     {
       /* Make sure all runs had the expected direction. */
       bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
       assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
       assert (bool (status_or  & kCTRunStatusRightToLeft) == backward);
     }
--- a/gfx/harfbuzz/src/hb-directwrite.cc
+++ b/gfx/harfbuzz/src/hb-directwrite.cc
@@ -1,10 +1,10 @@
 /*
- * Copyright © 2015-2016  Ebrahim Byagowi
+ * Copyright © 2015-2018  Ebrahim Byagowi
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
@@ -27,165 +27,173 @@
 #define HB_SHAPER directwrite
 #include "hb-shaper-impl-private.hh"
 
 #include <DWrite_1.h>
 
 #include "hb-directwrite.h"
 
 
-HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, face)
-HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, font)
+HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, face)
+HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, font)
+
+
+/*
+ * hb-directwrite uses new/delete syntatically but as we let users
+ * to override malloc/free, we will redefine new/delete so users
+ * won't need to do that by their own.
+ */
+void* operator new (size_t size) { return malloc (size); }
+void* operator new [] (size_t size) { return malloc (size); }
+void operator delete (void* pointer) { free (pointer); }
+void operator delete [] (void* pointer) { free (pointer); }
 
 
 /*
  * DirectWrite font stream helpers
  */
 
 // This is a font loader which provides only one font (unlike its original design).
 // For a better implementation which was also source of this
 // and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
 class DWriteFontFileLoader : public IDWriteFontFileLoader
 {
 private:
   IDWriteFontFileStream *mFontFileStream;
 public:
-  DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
+  DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
+  {
     mFontFileStream = fontFileStream;
   }
 
   // IUnknown interface
-  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
-  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
-  IFACEMETHOD_(ULONG, Release)() { return 1; }
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
+  IFACEMETHOD_ (ULONG, Release) () { return 1; }
 
   // IDWriteFontFileLoader methods
-  virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
-    UINT32 fontFileReferenceKeySize,
+  virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey (void const* fontFileReferenceKey,
+    uint32_t fontFileReferenceKeySize,
     OUT IDWriteFontFileStream** fontFileStream)
   {
     *fontFileStream = mFontFileStream;
     return S_OK;
   }
 };
 
 class DWriteFontFileStream : public IDWriteFontFileStream
 {
 private:
   uint8_t *mData;
   uint32_t mSize;
 public:
-  DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
+  DWriteFontFileStream (uint8_t *aData, uint32_t aSize)
   {
     mData = aData;
     mSize = aSize;
   }
 
   // IUnknown interface
-  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
-  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
-  IFACEMETHOD_(ULONG, Release)() { return 1; }
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
+  IFACEMETHOD_ (ULONG, Release) () { return 1; }
 
   // IDWriteFontFileStream methods
-  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
+  virtual HRESULT STDMETHODCALLTYPE ReadFileFragment (void const** fragmentStart,
     UINT64 fileOffset,
     UINT64 fragmentSize,
     OUT void** fragmentContext)
   {
     // We are required to do bounds checking.
-    if (fileOffset + fragmentSize > mSize) {
+    if (fileOffset + fragmentSize > mSize)
       return E_FAIL;
-    }
 
     // truncate the 64 bit fileOffset to size_t sized index into mData
     size_t index = static_cast<size_t> (fileOffset);
 
     // We should be alive for the duration of this.
     *fragmentStart = &mData[index];
     *fragmentContext = nullptr;
     return S_OK;
   }
 
-  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
+  virtual void STDMETHODCALLTYPE ReleaseFileFragment (void* fragmentContext) { }
 
-  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
+  virtual HRESULT STDMETHODCALLTYPE GetFileSize (OUT UINT64* fileSize)
   {
     *fileSize = mSize;
     return S_OK;
   }
 
-  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
+  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime (OUT UINT64* lastWriteTime)
   {
     return E_NOTIMPL;
   }
 };
 
 
 /*
 * shaper face data
 */
 
-struct hb_directwrite_shaper_face_data_t {
+struct hb_directwrite_shaper_face_data_t
+{
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   IDWriteFontFileStream *fontFileStream;
   IDWriteFontFileLoader *fontFileLoader;
   IDWriteFontFace *fontFace;
   hb_blob_t *faceBlob;
 };
 
 hb_directwrite_shaper_face_data_t *
-_hb_directwrite_shaper_face_data_create(hb_face_t *face)
+_hb_directwrite_shaper_face_data_create (hb_face_t *face)
 {
-  hb_directwrite_shaper_face_data_t *data =
-    (hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
+  hb_directwrite_shaper_face_data_t *data = new hb_directwrite_shaper_face_data_t;
   if (unlikely (!data))
     return nullptr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
   DWriteCreateFactory (
     DWRITE_FACTORY_TYPE_SHARED,
     __uuidof (IDWriteFactory),
     (IUnknown**) &dwriteFactory
   );
 
   HRESULT hr;
   hb_blob_t *blob = hb_face_reference_blob (face);
-  IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
-    (uint8_t*) hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob));
+  DWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
+    (uint8_t *) hb_blob_get_data (blob, nullptr),
+    hb_blob_get_length (blob));
 
-  IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
+  DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
   dwriteFactory->RegisterFontFileLoader (fontFileLoader);
 
   IDWriteFontFile *fontFile;
   uint64_t fontFileKey = 0;
   hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
       fontFileLoader, &fontFile);
 
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
-    return false; \
+    return nullptr; \
   } HB_STMT_END;
 
-  if (FAILED (hr)) {
+  if (FAILED (hr))
     FAIL ("Failed to load font file from data!");
-    return false;
-  }
 
   BOOL isSupported;
   DWRITE_FONT_FILE_TYPE fileType;
   DWRITE_FONT_FACE_TYPE faceType;
-  UINT32 numberOfFaces;
+  uint32_t numberOfFaces;
   hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
-  if (FAILED (hr) || !isSupported) {
+  if (FAILED (hr) || !isSupported)
     FAIL ("Font file is not supported.");
-    return false;
-  }
 
 #undef FAIL
 
   IDWriteFontFace *fontFace;
   dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
     DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
 
   data->dwriteFactory = dwriteFactory;
@@ -194,62 +202,63 @@ hb_directwrite_shaper_face_data_t *
   data->fontFileLoader = fontFileLoader;
   data->fontFace = fontFace;
   data->faceBlob = blob;
 
   return data;
 }
 
 void
-_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
+_hb_directwrite_shaper_face_data_destroy (hb_directwrite_shaper_face_data_t *data)
 {
   if (data->fontFace)
     data->fontFace->Release ();
   if (data->fontFile)
     data->fontFile->Release ();
-  if (data->dwriteFactory) {
+  if (data->dwriteFactory)
+  {
     if (data->fontFileLoader)
       data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
     data->dwriteFactory->Release ();
   }
   if (data->fontFileLoader)
     delete data->fontFileLoader;
   if (data->fontFileStream)
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
   if (data)
-    free (data);
+    delete data;
 }
 
 
 /*
  * shaper font data
  */
 
-struct hb_directwrite_shaper_font_data_t {
+struct hb_directwrite_shaper_font_data_t
+{
 };
 
 hb_directwrite_shaper_font_data_t *
 _hb_directwrite_shaper_font_data_create (hb_font_t *font)
 {
   if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
 
-  hb_directwrite_shaper_font_data_t *data =
-    (hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
+  hb_directwrite_shaper_font_data_t *data = new hb_directwrite_shaper_font_data_t;
   if (unlikely (!data))
     return nullptr;
 
   return data;
 }
 
 void
 _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
 {
-  free (data);
+  delete data;
 }
 
 
 /*
  * shaper shape_plan data
  */
 
 struct hb_directwrite_shaper_shape_plan_data_t {};
@@ -271,240 +280,238 @@ void
 
 // Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
 // but now is relicensed to MIT for HarfBuzz use
 class TextAnalysis
   : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
 {
 public:
 
-  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
-  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
-  IFACEMETHOD_(ULONG, Release)() { return 1; }
+  IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
+  IFACEMETHOD_ (ULONG, Release) () { return 1; }
 
-  // A single contiguous run of characters containing the same analysis 
+  // A single contiguous run of characters containing the same analysis
   // results.
   struct Run
   {
     uint32_t mTextStart;   // starting text position of this run
     uint32_t mTextLength;  // number of contiguous code units covered
     uint32_t mGlyphStart;  // starting glyph in the glyphs array
-    uint32_t mGlyphCount;  // number of glyphs associated with this run of 
+    uint32_t mGlyphCount;  // number of glyphs associated with this run
     // text
     DWRITE_SCRIPT_ANALYSIS mScript;
     uint8_t mBidiLevel;
     bool mIsSideways;
 
-    inline bool ContainsTextPosition(uint32_t aTextPosition) const
+    inline bool ContainsTextPosition (uint32_t aTextPosition) const
     {
-      return aTextPosition >= mTextStart
-        && aTextPosition <  mTextStart + mTextLength;
+      return aTextPosition >= mTextStart &&
+	     aTextPosition <  mTextStart + mTextLength;
     }
 
     Run *nextRun;
   };
 
 public:
-  TextAnalysis(const wchar_t* text,
+  TextAnalysis (const wchar_t* text,
     uint32_t textLength,
     const wchar_t* localeName,
     DWRITE_READING_DIRECTION readingDirection)
-    : mText(text)
-    , mTextLength(textLength)
-    , mLocaleName(localeName)
-    , mReadingDirection(readingDirection)
-    , mCurrentRun(nullptr) { };
+    : mText (text)
+    , mTextLength (textLength)
+    , mLocaleName (localeName)
+    , mReadingDirection (readingDirection)
+    , mCurrentRun (nullptr) { };
 
-  ~TextAnalysis() {
+  ~TextAnalysis ()
+  {
     // delete runs, except mRunHead which is part of the TextAnalysis object
-    for (Run *run = mRunHead.nextRun; run;) {
+    for (Run *run = mRunHead.nextRun; run;)
+    {
       Run *origRun = run;
       run = run->nextRun;
-      free (origRun);
+      delete origRun;
     }
   }
 
-  STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
-    Run **runHead) {
+  STDMETHODIMP GenerateResults (IDWriteTextAnalyzer* textAnalyzer,
+    Run **runHead)
+  {
     // Analyzes the text using the script analyzer and returns
     // the result as a series of runs.
 
     HRESULT hr = S_OK;
 
     // Initially start out with one result that covers the entire range.
     // This result will be subdivided by the analysis processes.
     mRunHead.mTextStart = 0;
     mRunHead.mTextLength = mTextLength;
     mRunHead.mBidiLevel =
       (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
     mRunHead.nextRun = nullptr;
     mCurrentRun = &mRunHead;
 
     // Call each of the analyzers in sequence, recording their results.
-    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
+    if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
       *runHead = &mRunHead;
-    }
 
     return hr;
   }
 
   // IDWriteTextAnalysisSource implementation
 
-  IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
+  IFACEMETHODIMP GetTextAtPosition (uint32_t textPosition,
     OUT wchar_t const** textString,
     OUT uint32_t* textLength)
   {
-    if (textPosition >= mTextLength) {
+    if (textPosition >= mTextLength)
+    {
       // No text at this position, valid query though.
       *textString = nullptr;
       *textLength = 0;
     }
-    else {
+    else
+    {
       *textString = mText + textPosition;
       *textLength = mTextLength - textPosition;
     }
     return S_OK;
   }
 
-  IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
+  IFACEMETHODIMP GetTextBeforePosition (uint32_t textPosition,
     OUT wchar_t const** textString,
     OUT uint32_t* textLength)
   {
-    if (textPosition == 0 || textPosition > mTextLength) {
+    if (textPosition == 0 || textPosition > mTextLength)
+    {
       // Either there is no text before here (== 0), or this
       // is an invalid position. The query is considered valid though.
       *textString = nullptr;
       *textLength = 0;
     }
-    else {
+    else
+    {
       *textString = mText;
       *textLength = textPosition;
     }
     return S_OK;
   }
 
-  IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
-    GetParagraphReadingDirection() { return mReadingDirection; }
+  IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
+    GetParagraphReadingDirection () { return mReadingDirection; }
 
-  IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
+  IFACEMETHODIMP GetLocaleName (uint32_t textPosition,
     uint32_t* textLength,
     wchar_t const** localeName)
   {
     return S_OK;
   }
 
   IFACEMETHODIMP
-    GetNumberSubstitution(uint32_t textPosition,
+    GetNumberSubstitution (uint32_t textPosition,
     OUT uint32_t* textLength,
     OUT IDWriteNumberSubstitution** numberSubstitution)
   {
     // We do not support number substitution.
     *numberSubstitution = nullptr;
     *textLength = mTextLength - textPosition;
 
     return S_OK;
   }
 
   // IDWriteTextAnalysisSink implementation
 
   IFACEMETHODIMP
-    SetScriptAnalysis(uint32_t textPosition,
+    SetScriptAnalysis (uint32_t textPosition,
     uint32_t textLength,
     DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
   {
-    SetCurrentRun(textPosition);
-    SplitCurrentRun(textPosition);
+    SetCurrentRun (textPosition);
+    SplitCurrentRun (textPosition);
     while (textLength > 0)
     {
-      Run *run = FetchNextRun(&textLength);
+      Run *run = FetchNextRun (&textLength);
       run->mScript = *scriptAnalysis;
     }
 
     return S_OK;
   }
 
   IFACEMETHODIMP
-    SetLineBreakpoints(uint32_t textPosition,
+    SetLineBreakpoints (uint32_t textPosition,
     uint32_t textLength,
     const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
 
-  IFACEMETHODIMP SetBidiLevel(uint32_t textPosition,
+  IFACEMETHODIMP SetBidiLevel (uint32_t textPosition,
     uint32_t textLength,
     uint8_t explicitLevel,
     uint8_t resolvedLevel) { return S_OK; }
 
   IFACEMETHODIMP
-    SetNumberSubstitution(uint32_t textPosition,
+    SetNumberSubstitution (uint32_t textPosition,
     uint32_t textLength,
     IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
 
 protected:
-  Run *FetchNextRun(IN OUT uint32_t* textLength)
+  Run *FetchNextRun (IN OUT uint32_t* textLength)
   {
     // Used by the sink setters, this returns a reference to the next run.
     // Position and length are adjusted to now point after the current run
     // being returned.
 
     Run *origRun = mCurrentRun;
     // Split the tail if needed (the length remaining is less than the
     // current run's size).
     if (*textLength < mCurrentRun->mTextLength)
-    {
       SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
-    }
     else
-    {
       // Just advance the current run.
       mCurrentRun = mCurrentRun->nextRun;
-    }
     *textLength -= origRun->mTextLength;
 
     // Return a reference to the run that was just current.
     return origRun;
   }
 
-  void SetCurrentRun(uint32_t textPosition)
+  void SetCurrentRun (uint32_t textPosition)
   {
     // Move the current run to the given position.
     // Since the analyzers generally return results in a forward manner,
     // this will usually just return early. If not, find the
     // corresponding run for the text position.
 
     if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
-    {
       return;
-    }
 
-    for (Run *run = &mRunHead; run; run = run->nextRun) {
+    for (Run *run = &mRunHead; run; run = run->nextRun)
       if (run->ContainsTextPosition (textPosition))
       {
-        mCurrentRun = run;
-        return;
+	mCurrentRun = run;
+	return;
       }
-    }
-    //NS_NOTREACHED("We should always be able to find the text position in one \
-            //                of our runs");
+    assert (0); // We should always be able to find the text position in one of our runs
   }
 
-  void SplitCurrentRun(uint32_t splitPosition)
+  void SplitCurrentRun (uint32_t splitPosition)
   {
     if (!mCurrentRun)
     {
-      //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
+      assert (0); // SplitCurrentRun called without current run
       // Shouldn't be calling this when no current run is set!
       return;
     }
     // Split the current run.
     if (splitPosition <= mCurrentRun->mTextStart)
     {
       // No need to split, already the start of a run
       // or before it. Usually the first.
       return;
     }
-    Run *newRun = (Run*) malloc (sizeof (Run));
+    Run *newRun = new Run;
 
     *newRun = *mCurrentRun;
 
     // Insert the new run in our linked list.
     newRun->nextRun = mCurrentRun->nextRun;
     mCurrentRun->nextRun = newRun;
 
     // Adjust runs' text positions and lengths.
@@ -529,320 +536,293 @@ protected:
 
   // Output is a list of runs starting here
   Run  mRunHead;
 };
 
 static inline uint16_t hb_uint16_swap (const uint16_t v)
 { return (v >> 8) | (v << 8); }
 static inline uint32_t hb_uint32_swap (const uint32_t v)
-{ return (hb_uint16_swap(v) << 16) | hb_uint16_swap(v >> 16); }
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
 
 /*
  * shaper
  */
 
 static hb_bool_t
-_hb_directwrite_shape_full(hb_shape_plan_t    *shape_plan,
+_hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
   hb_font_t          *font,
   hb_buffer_t        *buffer,
   const hb_feature_t *features,
   unsigned int        num_features,
   float               lineWidth)
 {
   hb_face_t *face = font->face;
   hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
   IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
   IDWriteFontFace *fontFace = face_data->fontFace;
 
   IDWriteTextAnalyzer* analyzer;
-  dwriteFactory->CreateTextAnalyzer(&analyzer);
+  dwriteFactory->CreateTextAnalyzer (&analyzer);
 
   unsigned int scratch_size;
   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
   { \
     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
     assert (_consumed <= scratch_size); \
     scratch += _consumed; \
     scratch_size -= _consumed; \
   }
 
 #define utf16_index() var1.u32
 
-  ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2);
+  ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
 
   unsigned int chars_len = 0;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
     hb_codepoint_t c = buffer->info[i].codepoint;
-    buffer->info[i].utf16_index() = chars_len;
-    if (likely(c <= 0xFFFFu))
+    buffer->info[i].utf16_index () = chars_len;
+    if (likely (c <= 0xFFFFu))
       textString[chars_len++] = c;
-    else if (unlikely(c > 0x10FFFFu))
+    else if (unlikely (c > 0x10FFFFu))
       textString[chars_len++] = 0xFFFDu;
-    else {
+    else
+    {
       textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
       textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
     }
   }
 
-  ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
-  // if (num_features)
+  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
+  /* Need log_clusters to assign features. */
+  chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
   {
-    /* Need log_clusters to assign features. */
-    chars_len = 0;
-    for (unsigned int i = 0; i < buffer->len; i++)
-    {
-      hb_codepoint_t c = buffer->info[i].codepoint;
-      unsigned int cluster = buffer->info[i].cluster;
-      log_clusters[chars_len++] = cluster;
-      if (hb_in_range(c, 0x10000u, 0x10FFFFu))
-        log_clusters[chars_len++] = cluster; /* Surrogates. */
-    }
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    unsigned int cluster = buffer->info[i].cluster;
+    log_clusters[chars_len++] = cluster;
+    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+      log_clusters[chars_len++] = cluster; /* Surrogates. */
   }
 
   // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
 
-  DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? 
+  DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
     DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
 
   /*
   * There's an internal 16-bit limit on some things inside the analyzer,
   * but we never attempt to shape a word longer than 64K characters
   * in a single gfxShapedWord, so we cannot exceed that limit.
   */
   uint32_t textLength = buffer->len;
 
-  TextAnalysis analysis(textString, textLength, nullptr, readingDirection);
+  TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
   TextAnalysis::Run *runHead;
   HRESULT hr;
-  hr = analysis.GenerateResults(analyzer, &runHead);
+  hr = analysis.GenerateResults (analyzer, &runHead);
 
 #define FAIL(...) \
   HB_STMT_START { \
     DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
     return false; \
   } HB_STMT_END;
 
   if (FAILED (hr))
-  {
     FAIL ("Analyzer failed to generate results.");
-    return false;
-  }
 
   uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
   uint32_t glyphCount;
   bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
 
   const wchar_t localeName[20] = {0};
   if (buffer->props.language != nullptr)
   {
     mbstowcs ((wchar_t*) localeName,
       hb_language_to_string (buffer->props.language), 20);
   }
 
-  DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
-  singleFeatures.featureCount = num_features;
+  // TODO: it does work but doesn't care about ranges
+  DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
+  typographic_features.featureCount = num_features;
   if (num_features)
   {
-    DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*)
-      malloc (sizeof (DWRITE_FONT_FEATURE) * num_features);
+    typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
     for (unsigned int i = 0; i < num_features; ++i)
     {
-      dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
-        hb_uint32_swap (features[i].tag);
-      dwfeatureArray[i].parameter = features[i].value;
+      typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
+	hb_uint32_swap (features[i].tag);
+      typographic_features.features[i].parameter = features[i].value;
     }
-    singleFeatures.features = dwfeatureArray;
   }
   const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
-    (const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
+    (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
   const uint32_t featureRangeLengths[] = { textLength };
+  //
 
-  uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
-  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
-    malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
+  uint16_t* clusterMap = new uint16_t[textLength];
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties =
+    new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
 retry_getglyphs:
-  uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
-  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
-    malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
+  uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties =
+    new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
 
   hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
     isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
     featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
     glyphProperties, &glyphCount);
 
   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
-    free (glyphIndices);
-    free (glyphProperties);
+    delete [] glyphIndices;
+    delete [] glyphProperties;
 
     maxGlyphCount *= 2;
 
     goto retry_getglyphs;
   }
   if (FAILED (hr))
-  {
     FAIL ("Analyzer failed to get glyphs.");
-    return false;
-  }
 
-  float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
-  DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*)
-    malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+  float* glyphAdvances = new float[maxGlyphCount];
+  DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
 
   /* The -2 in the following is to compensate for possible
-   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
-  unsigned int glyphs_size = (scratch_size * sizeof(int) - 2)
-         / (sizeof(WORD) +
-            sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES) +
-            sizeof(int) +
-            sizeof(DWRITE_GLYPH_OFFSET) +
-            sizeof(uint32_t));
+   * alignment needed after the WORD array.  sizeof (WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
+         / (sizeof (WORD) +
+            sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
+            sizeof (int) +
+            sizeof (DWRITE_GLYPH_OFFSET) +
+            sizeof (uint32_t));
   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
 
 #undef ALLOCATE_ARRAY
 
-  int fontEmSize = font->face->get_upem();
+  int fontEmSize = font->face->get_upem ();
   if (fontEmSize < 0)
     fontEmSize = -fontEmSize;
 
   if (fontEmSize < 0)
     fontEmSize = -fontEmSize;
   double x_mult = (double) font->x_scale / fontEmSize;
   double y_mult = (double) font->y_scale / fontEmSize;
 
   hr = analyzer->GetGlyphPlacements (textString,
     clusterMap, textProperties, textLength, glyphIndices,
     glyphProperties, glyphCount, fontFace, fontEmSize,
     false, isRightToLeft, &runHead->mScript, localeName,
     &dwFeatures, featureRangeLengths, 1,
     glyphAdvances, glyphOffsets);
 
   if (FAILED (hr))
-  {
     FAIL ("Analyzer failed to get glyph placements.");
-    return false;
-  }
 
   IDWriteTextAnalyzer1* analyzer1;
   analyzer->QueryInterface (&analyzer1);
 
   if (analyzer1 && lineWidth)
   {
 
     DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
-      (DWRITE_JUSTIFICATION_OPPORTUNITY*)
-      malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
+      new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
     hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
       runHead->mScript, textLength, glyphCount, textString, clusterMap,
       glyphProperties, justificationOpportunities);
 
     if (FAILED (hr))
-    {
       FAIL ("Analyzer failed to get justification opportunities.");
-      return false;
-    }
 
-    float* justifiedGlyphAdvances =
-      (float*) malloc (maxGlyphCount * sizeof (float));
-    DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
-      malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+    float* justifiedGlyphAdvances = new float[maxGlyphCount];
+    DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
     hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
       glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
 
     if (FAILED (hr))
-    {
-      FAIL("Analyzer failed to get justified glyph advances.");
-      return false;
-    }
+      FAIL ("Analyzer failed to get justified glyph advances.");
 
     DWRITE_SCRIPT_PROPERTIES scriptProperties;
     hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
     if (FAILED (hr))
-    {
-      FAIL("Analyzer failed to get script properties.");
-      return false;
-    }
+      FAIL ("Analyzer failed to get script properties.");
     uint32_t justificationCharacter = scriptProperties.justificationCharacter;
 
     // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
     if (justificationCharacter != 32)
     {
-      uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
+      uint16_t* modifiedClusterMap = new uint16_t[textLength];
     retry_getjustifiedglyphs:
-      uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
-      float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
-      DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
-        malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
+      uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
+      float* modifiedGlyphAdvances = new float[maxGlyphCount];
+      DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets =
+	new DWRITE_GLYPH_OFFSET[maxGlyphCount];
       uint32_t actualGlyphsCount;
       hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
-        textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
-        glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
-        glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
-        modifiedGlyphAdvances, modifiedGlyphOffsets);
+	textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
+	glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
+	glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
+	modifiedGlyphAdvances, modifiedGlyphOffsets);
 
       if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
       {
-        maxGlyphCount = actualGlyphsCount;
-        free (modifiedGlyphIndices);
-        free (modifiedGlyphAdvances);
-        free (modifiedGlyphOffsets);
+	maxGlyphCount = actualGlyphsCount;
+	delete [] modifiedGlyphIndices;
+	delete [] modifiedGlyphAdvances;
+	delete [] modifiedGlyphOffsets;
 
-        maxGlyphCount = actualGlyphsCount;
+	maxGlyphCount = actualGlyphsCount;
 
-        goto retry_getjustifiedglyphs;
+	goto retry_getjustifiedglyphs;
       }
       if (FAILED (hr))
-      {
-        FAIL ("Analyzer failed to get justified glyphs.");
-        return false;
-      }
+	FAIL ("Analyzer failed to get justified glyphs.");
 
-      free (clusterMap);
-      free (glyphIndices);
-      free (glyphAdvances);
-      free (glyphOffsets);
+      delete [] clusterMap;
+      delete [] glyphIndices;
+      delete [] glyphAdvances;
+      delete [] glyphOffsets;
 
       glyphCount = actualGlyphsCount;
       clusterMap = modifiedClusterMap;
       glyphIndices = modifiedGlyphIndices;
       glyphAdvances = modifiedGlyphAdvances;
       glyphOffsets = modifiedGlyphOffsets;
 
-      free (justifiedGlyphAdvances);
-      free (justifiedGlyphOffsets);
+      delete [] justifiedGlyphAdvances;
+      delete [] justifiedGlyphOffsets;
     }
     else
     {
-      free (glyphAdvances);
-      free (glyphOffsets);
+      delete [] glyphAdvances;
+      delete [] glyphOffsets;
 
       glyphAdvances = justifiedGlyphAdvances;
       glyphOffsets = justifiedGlyphOffsets;
     }
 
-    free (justificationOpportunities);
+    delete [] justificationOpportunities;
 
   }
 
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
 
   /* Calculate visual-clusters.  That's what we ship. */
   for (unsigned int i = 0; i < glyphCount; i++)
     vis_clusters[i] = -1;
   for (unsigned int i = 0; i < buffer->len; i++)
   {
     uint32_t *p =
-      &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
+      &vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
     *p = MIN (*p, buffer->info[i].cluster);
   }
   for (unsigned int i = 1; i < glyphCount; i++)
     if (vis_clusters[i] == -1)
       vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
 
@@ -878,53 +858,53 @@ retry_getglyphs:
     pos->x_offset =
       x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
     pos->y_offset = y_mult * info->var2.i32;
   }
 
   if (isRightToLeft)
     hb_buffer_reverse (buffer);
 
-  free (clusterMap);
-  free (glyphIndices);
-  free (textProperties);
-  free (glyphProperties);
-  free (glyphAdvances);
-  free (glyphOffsets);
+  delete [] clusterMap;
+  delete [] glyphIndices;
+  delete [] textProperties;
+  delete [] glyphProperties;
+  delete [] glyphAdvances;
+  delete [] glyphOffsets;
 
   if (num_features)
-    free (singleFeatures.features);
+    delete [] typographic_features.features;
 
   /* Wow, done! */
   return true;
 }
 
 hb_bool_t
-_hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
+_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
   hb_font_t          *font,
   hb_buffer_t        *buffer,
   const hb_feature_t *features,
   unsigned int        num_features)
 {
-  return _hb_directwrite_shape_full(shape_plan, font, buffer,
+  return _hb_directwrite_shape_full (shape_plan, font, buffer,
     features, num_features, 0);
 }
 
 /*
  * Public [experimental] API
  */
 
 hb_bool_t
-hb_directwrite_shape_experimental_width(hb_font_t          *font,
+hb_directwrite_shape_experimental_width (hb_font_t          *font,
   hb_buffer_t        *buffer,
   const hb_feature_t *features,
   unsigned int        num_features,
   float               width)
 {
-  static char *shapers = "directwrite";
+  static const char *shapers = "directwrite";
   hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
     &buffer->props, features, num_features, &shapers);
   hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
     features, num_features, width);
 
   buffer->unsafe_to_break_all ();
 
   return res;
--- a/gfx/harfbuzz/src/hb-directwrite.h
+++ b/gfx/harfbuzz/src/hb-directwrite.h
@@ -25,14 +25,15 @@
 #ifndef HB_DIRECTWRITE_H
 #define HB_DIRECTWRITE_H
 
 #include "hb.h"
 
 HB_BEGIN_DECLS
 
 HB_EXTERN hb_bool_t
-hb_directwrite_shape_experimental_width(hb_font_t *font, hb_buffer_t *buffer,
-  const hb_feature_t *features, unsigned int num_features, float width);
+hb_directwrite_shape_experimental_width (hb_font_t *font, hb_buffer_t *buffer,
+					 const hb_feature_t *features,
+					 unsigned int num_features, float width);
 
 HB_END_DECLS
 
 #endif /* HB_DIRECTWRITE_H */
--- a/gfx/harfbuzz/src/hb-dsalgs.hh
+++ b/gfx/harfbuzz/src/hb-dsalgs.hh
@@ -44,17 +44,17 @@ hb_bsearch_r (const void *key, const voi
     int c = compar (key, p, arg);
     if (c < 0)
       max = mid - 1;
     else if (c > 0)
       min = mid + 1;
     else
       return (void *) p;
   }
-  return NULL;
+  return nullptr;
 }
 
 
 
 /* From https://github.com/noporpoise/sort_r */
 
 /* Isaac Turner 29 April 2014 Public Domain */
 
--- a/gfx/harfbuzz/src/hb-face.cc
+++ b/gfx/harfbuzz/src/hb-face.cc
@@ -24,21 +24,45 @@
  *
  * Red Hat Author(s): Behdad Esfahbod
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
 #include "hb-face-private.hh"
+#include "hb-blob-private.hh"
 #include "hb-open-file-private.hh"
 #include "hb-ot-head-table.hh"
 #include "hb-ot-maxp-table.hh"
 
 
+
+/**
+ * hb_face_count: Get number of faces on the blob
+ * @blob:
+ *
+ *
+ *
+ * Return value: Number of faces on the blob
+ *
+ * Since: 1.7.7
+ **/
+unsigned int
+hb_face_count (hb_blob_t *blob)
+{
+  if (unlikely (!blob))
+    return 0;
+
+  hb_blob_t *sanitized = OT::Sanitizer<OT::OpenTypeFontFile> ().sanitize (blob);
+  const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
+
+  return ot.get_face_count ();
+}
+
 /*
  * hb_face_t
  */
 
 const hb_face_t _hb_face_nil = {
   HB_OBJECT_HEADER_STATIC,
 
   true, /* immutable */
@@ -59,20 +83,20 @@ const hb_face_t _hb_face_nil = {
 
   nullptr, /* shape_plans */
 };
 
 
 /**
  * hb_face_create_for_tables:
  * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data: 
- * @destroy: 
+ * @user_data:
+ * @destroy:
  *
- * 
+ *
  *
  * Return value: (transfer full)
  *
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
 			   void                      *user_data,
@@ -129,32 +153,32 @@ static void
 static hb_blob_t *
 _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
   hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
 
   if (tag == HB_TAG_NONE)
     return hb_blob_reference (data->blob);
 
-  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
   const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
 
   const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
 
   hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
 
   return blob;
 }
 
 /**
  * hb_face_create: (Xconstructor)
- * @blob: 
- * @index: 
+ * @blob:
+ * @index:
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_create (hb_blob_t    *blob,
 		unsigned int  index)
@@ -176,50 +200,50 @@ hb_face_create (hb_blob_t    *blob,
   face->index = index;
 
   return face;
 }
 
 /**
  * hb_face_get_empty:
  *
- * 
+ *
  *
  * Return value: (transfer full)
  *
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_get_empty (void)
 {
   return const_cast<hb_face_t *> (&_hb_face_nil);
 }
 
 
 /**
  * hb_face_reference: (skip)
  * @face: a face.
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_face_reference (hb_face_t *face)
 {
   return hb_object_reference (face);
 }
 
 /**
  * hb_face_destroy: (skip)
  * @face: a face.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_face_destroy (hb_face_t *face)
 {
   if (!hb_object_destroy (face)) return;
 
@@ -239,129 +263,129 @@ hb_face_destroy (hb_face_t *face)
     face->destroy (face->user_data);
 
   free (face);
 }
 
 /**
  * hb_face_set_user_data: (skip)
  * @face: a face.
- * @key: 
- * @data: 
- * @destroy: 
- * @replace: 
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_face_set_user_data (hb_face_t          *face,
 		       hb_user_data_key_t *key,
 		       void *              data,
 		       hb_destroy_func_t   destroy,
 		       hb_bool_t           replace)
 {
   return hb_object_set_user_data (face, key, data, destroy, replace);
 }
 
 /**
  * hb_face_get_user_data: (skip)
  * @face: a face.
- * @key: 
+ * @key:
  *
- * 
+ *
  *
  * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
 void *
 hb_face_get_user_data (hb_face_t          *face,
 		       hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (face, key);
 }
 
 /**
  * hb_face_make_immutable:
  * @face: a face.
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_face_make_immutable (hb_face_t *face)
 {
   if (unlikely (hb_object_is_inert (face)))
     return;
 
   face->immutable = true;
 }
 
 /**
  * hb_face_is_immutable:
  * @face: a face.
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 hb_bool_t
 hb_face_is_immutable (hb_face_t *face)
 {
   return face->immutable;
 }
 
 
 /**
  * hb_face_reference_table:
  * @face: a face.
- * @tag: 
+ * @tag:
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
 hb_blob_t *
 hb_face_reference_table (hb_face_t *face,
 			 hb_tag_t   tag)
 {
   return face->reference_table (tag);
 }
 
 /**
  * hb_face_reference_blob:
  * @face: a face.
  *
- * 
+ *
  *
  * Return value: (transfer full):
  *
  * Since: 0.9.2
  **/
 hb_blob_t *
 hb_face_reference_blob (hb_face_t *face)
 {
   return face->reference_table (HB_TAG_NONE);
 }
 
 /**
  * hb_face_set_index:
  * @face: a face.
- * @index: 
+ * @index:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_face_set_index (hb_face_t    *face,
 		   unsigned int  index)
 {
   if (face->immutable)
@@ -369,34 +393,34 @@ hb_face_set_index (hb_face_t    *face,
 
   face->index = index;
 }
 
 /**
  * hb_face_get_index:
  * @face: a face.
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 unsigned int
 hb_face_get_index (hb_face_t    *face)
 {
   return face->index;
 }
 
 /**
  * hb_face_set_upem:
  * @face: a face.
- * @upem: 
+ * @upem:
  *
- * 
+ *
  *
  * Since: 0.9.2
  **/
 void
 hb_face_set_upem (hb_face_t    *face,
 		  unsigned int  upem)
 {
   if (face->immutable)
@@ -404,43 +428,43 @@ hb_face_set_upem (hb_face_t    *face,
 
   face->upem = upem;
 }
 
 /**
  * hb_face_get_upem:
  * @face: a face.
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.2
  **/
 unsigned int
 hb_face_get_upem (hb_face_t *face)
 {
   return face->get_upem ();
 }
 
 void
 hb_face_t::load_upem (void) const
 {
   hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head));
-  const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+  const OT::head *head_table = head_blob->as<OT::head> ();
   upem = head_table->get_upem ();
   hb_blob_destroy (head_blob);
 }
 
 /**
  * hb_face_set_glyph_count:
  * @face: a face.
- * @glyph_count: 
+ * @glyph_count:
  *
- * 
+ *
  *
  * Since: 0.9.7
  **/
 void
 hb_face_set_glyph_count (hb_face_t    *face,
 			 unsigned int  glyph_count)
 {
   if (face->immutable)
@@ -448,33 +472,33 @@ hb_face_set_glyph_count (hb_face_t    *f
 
   face->num_glyphs = glyph_count;
 }
 
 /**
  * hb_face_get_glyph_count:
  * @face: a face.
  *
- * 
+ *
  *
- * Return value: 
+ * Return value:
  *
  * Since: 0.9.7
  **/
 unsigned int
 hb_face_get_glyph_count (hb_face_t *face)
 {
   return face->get_num_glyphs ();
 }
 
 void
 hb_face_t::load_num_glyphs (void) const
 {
   hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp));
-  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+  const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
   num_glyphs = maxp_table->get_num_glyphs ();
   hb_blob_destroy (maxp_blob);
 }
 
 /**
  * hb_face_get_table_tags:
  * @face: a face.
  *
@@ -485,22 +509,22 @@ hb_face_t::load_num_glyphs (void) const
  * Since: 1.6.0
  **/
 unsigned int
 hb_face_get_table_tags (hb_face_t    *face,
 			unsigned int  start_offset,
 			unsigned int *table_count, /* IN/OUT */
 			hb_tag_t     *table_tags /* OUT */)
 {
-  if (face->destroy != _hb_face_for_data_closure_destroy)
+  if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
   {
     if (table_count)
       *table_count = 0;
     return 0;
   }
 
   hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
 
-  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
   const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
 
   return ot_face.get_table_tags (start_offset, table_count, table_tags);
 }
--- a/gfx/harfbuzz/src/hb-face.h
+++ b/gfx/harfbuzz/src/hb-face.h
@@ -32,16 +32,20 @@
 #define HB_FACE_H
 
 #include "hb-common.h"
 #include "hb-blob.h"
 
 HB_BEGIN_DECLS
 
 
+HB_EXTERN unsigned int
+hb_face_count (hb_blob_t *blob);
+
+
 /*
  * hb_face_t
  */
 
 typedef struct hb_face_t hb_face_t;
 
 HB_EXTERN hb_face_t *
 hb_face_create (hb_blob_t    *blob,
--- a/gfx/harfbuzz/src/hb-font-private.hh
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -78,17 +78,21 @@ struct hb_font_funcs_t {
 
   /* Don't access these directly.  Call font->get_*() instead. */
   union get_t {
     struct get_funcs_t {
 #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
       HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
     } f;
-    void (*array[VAR]) (void);
+    void (*array[0
+#define HB_FONT_FUNC_IMPLEMENT(name) +1
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+		]) (void);
   } get;
 };
 
 
 
 /*
  * hb_font_t
  */
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -122,34 +122,34 @@ hb_font_get_variation_glyph_parent (hb_f
 				    hb_codepoint_t *glyph,
 				    void *user_data HB_UNUSED)
 {
   return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
 }
 
 
 static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_h_advance_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
   return font->x_scale;
 }
 static hb_position_t
 hb_font_get_glyph_h_advance_parent (hb_font_t *font,
 				    void *font_data HB_UNUSED,
 				    hb_codepoint_t glyph,
 				    void *user_data HB_UNUSED)
 {
   return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
 }
 
 static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
+hb_font_get_glyph_v_advance_nil (hb_font_t *font,
 				 void *font_data HB_UNUSED,
 				 hb_codepoint_t glyph,
 				 void *user_data HB_UNUSED)
 {
   /* TODO use font_extents.ascender+descender */
   return font->y_scale;
 }
 static hb_position_t
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -104,58 +104,58 @@ static void
   free (ft_font);
 }
 
 /**
  * hb_ft_font_set_load_flags:
  * @font:
  * @load_flags:
  *
- * 
+ *
  *
  * Since: 1.0.5
  **/
 void
 hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
 {
   if (font->immutable)
     return;
 
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
 
   ft_font->load_flags = load_flags;
 }
 
 /**
  * hb_ft_font_get_load_flags:
  * @font:
  *
- * 
+ *
  *
  * Return value:
  * Since: 1.0.5
  **/
 int
 hb_ft_font_get_load_flags (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return 0;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 
   return ft_font->load_flags;
 }
 
 FT_Face
 hb_ft_font_get_face (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return nullptr;
 
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
 
   return ft_font->ft_face;
 }
 
 
@@ -172,17 +172,17 @@ hb_ft_get_nominal_glyph (hb_font_t *font
 
   if (unlikely (!g))
   {
     if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
     {
       /* For symbol-encoded OpenType fonts, we duplicate the
        * U+F000..F0FF range at U+0000..U+00FF.  That's what
        * Windows seems to do, and that's hinted about at:
-       * http://www.microsoft.com/typography/otspec/recom.htm
+       * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
        * under "Non-Standard (Symbol) Fonts". */
       g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
       if (!g)
 	return false;
     }
     else
       return false;
   }
@@ -205,17 +205,17 @@ hb_ft_get_variation_glyph (hb_font_t *fo
   if (unlikely (!g))
     return false;
 
   *glyph = g;
   return true;
 }
 
 static hb_position_t
-hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_h_advance (hb_font_t *font,
 			   void *font_data,
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Fixed v;
 
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
@@ -223,17 +223,17 @@ hb_ft_get_glyph_h_advance (hb_font_t *fo
 
   if (font->x_scale < 0)
     v = -v;
 
   return (v + (1<<9)) >> 10;
 }
 
 static hb_position_t
-hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_v_advance (hb_font_t *font,
 			   void *font_data,
 			   hb_codepoint_t glyph,
 			   void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Fixed v;
 
   if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
@@ -243,17 +243,17 @@ hb_ft_get_glyph_v_advance (hb_font_t *fo
     v = -v;
 
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
   return (-v + (1<<9)) >> 10;
 }
 
 static hb_bool_t
-hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_v_origin (hb_font_t *font,
 			  void *font_data,
 			  hb_codepoint_t glyph,
 			  hb_position_t *x,
 			  hb_position_t *y,
 			  void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Face ft_face = ft_font->ft_face;
@@ -287,17 +287,17 @@ hb_ft_get_glyph_h_kerning (hb_font_t *fo
   FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
   if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
     return 0;
 
   return kerningv.x;
 }
 
 static hb_bool_t
-hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_extents (hb_font_t *font,
 			 void *font_data,
 			 hb_codepoint_t glyph,
 			 hb_glyph_extents_t *extents,
 			 void *user_data HB_UNUSED)
 {
   const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
   FT_Face ft_face = ft_font->ft_face;
 
@@ -418,17 +418,22 @@ hb_ft_get_font_h_extents (hb_font_t *fon
 }
 
 static hb_font_funcs_t *static_ft_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_ft_funcs (void)
 {
-  hb_font_funcs_destroy (static_ft_funcs);
+retry:
+  hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
+  if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr))
+    goto retry;
+
+  hb_font_funcs_destroy (ft_funcs);
 }
 #endif
 
 static void
 _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
 {
 retry:
   hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
@@ -497,22 +502,22 @@ reference_table  (hb_face_t *face HB_UNU
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
 			 buffer, free);
 }
 
 /**
  * hb_ft_face_create:
- * @ft_face: (destroy destroy) (scope notified): 
+ * @ft_face: (destroy destroy) (scope notified):
  * @destroy:
  *
- * 
+ *
  *
- * Return value: (transfer full): 
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy)
 {
   hb_face_t *face;
 
@@ -534,19 +539,19 @@ hb_ft_face_create (FT_Face           ft_
 
   return face;
 }
 
 /**
  * hb_ft_face_create_referenced:
  * @ft_face:
  *
- * 
+ *
  *
- * Return value: (transfer full): 
+ * Return value: (transfer full):
  * Since: 0.9.38
  **/
 hb_face_t *
 hb_ft_face_create_referenced (FT_Face ft_face)
 {
   FT_Reference_Face (ft_face);
   return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
 }
@@ -554,21 +559,21 @@ hb_ft_face_create_referenced (FT_Face ft
 static void
 hb_ft_face_finalize (FT_Face ft_face)
 {
   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 }
 
 /**
  * hb_ft_face_create_cached:
- * @ft_face: 
+ * @ft_face:
+ *
  *
- * 
  *
- * Return value: (transfer full): 
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face)
 {
   if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
   {
     if (ft_face->generic.finalizer)
@@ -579,22 +584,22 @@ hb_ft_face_create_cached (FT_Face ft_fac
   }
 
   return hb_face_reference ((hb_face_t *) ft_face->generic.data);
 }
 
 
 /**
  * hb_ft_font_create:
- * @ft_face: (destroy destroy) (scope notified): 
+ * @ft_face: (destroy destroy) (scope notified):
  * @destroy:
  *
- * 
+ *
  *
- * Return value: (transfer full): 
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
 		   hb_destroy_func_t destroy)
 {
   hb_font_t *font;
   hb_face_t *face;
@@ -605,17 +610,17 @@ hb_ft_font_create (FT_Face           ft_
   _hb_ft_font_set_funcs (font, ft_face, false);
   hb_ft_font_changed (font);
   return font;
 }
 
 void
 hb_ft_font_changed (hb_font_t *font)
 {
-  if (font->destroy != _hb_ft_font_destroy)
+  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
     return;
 
   hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
   FT_Face ft_face = ft_font->ft_face;
 
   hb_font_set_scale (font,
 		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
 		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
@@ -659,19 +664,19 @@ hb_ft_font_changed (hb_font_t *font)
   }
 #endif
 }
 
 /**
  * hb_ft_font_create_referenced:
  * @ft_face:
  *
- * 
+ *
  *
- * Return value: (transfer full): 
+ * Return value: (transfer full):
  * Since: 0.9.38
  **/
 hb_font_t *
 hb_ft_font_create_referenced (FT_Face ft_face)
 {
   FT_Reference_Face (ft_face);
   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 }
@@ -680,17 +685,22 @@ hb_ft_font_create_referenced (FT_Face ft
 /* Thread-safe, lock-free, FT_Library */
 
 static FT_Library ft_library;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_ft_library (void)
 {
-  FT_Done_FreeType (ft_library);
+retry:
+  FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
+  if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
+    goto retry;
+
+  FT_Done_FreeType (library);
 }
 #endif
 
 static FT_Library
 get_ft_library (void)
 {
 retry:
   FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -365,17 +365,22 @@ hb_glib_unicode_decompose_compatibility 
 }
 
 static hb_unicode_funcs_t *static_glib_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_glib_funcs (void)
 {
-  hb_unicode_funcs_destroy (static_glib_funcs);
+retry:
+  hb_unicode_funcs_t *glib_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
+  if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, glib_funcs, nullptr))
+    goto retry;
+
+  hb_unicode_funcs_destroy (glib_funcs);
 }
 #endif
 
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
 retry:
   hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -74,20 +74,22 @@ static const void *hb_graphite2_get_tabl
     hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
       return nullptr;
     }
     p->blob = blob;
     p->tag = tag;
 
-    /* TODO Not thread-safe, but fairly harmless.
-     * We can do the double-checked pointer cmpexch thing here. */
-    p->next = face_data->tlist;
-    face_data->tlist = p;
+retry:
+    hb_graphite2_tablelist_t *tlist = (hb_graphite2_tablelist_t *) hb_atomic_ptr_get (&face_data->tlist);
+    p->next = tlist;
+
+    if (!hb_atomic_ptr_cmpexch (&face_data->tlist, tlist, p))
+      goto retry;
   }
 
   unsigned int tlen;
   const char *d = hb_blob_get_data (blob, &tlen);
   *len = tlen;
   return d;
 }
 
@@ -376,38 +378,38 @@ hb_bool_t
   if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
     curradvx = 0;
     for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
     {
       pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
       if (info->cluster != currclus) {
-        pPos->x_advance = info->var1.i32 * xscale;
-        curradvx += pPos->x_advance;
-        currclus = info->cluster;
+	pPos->x_advance = info->var1.i32 * xscale;
+	curradvx += pPos->x_advance;
+	currclus = info->cluster;
       } else
-        pPos->x_advance = 0.;
+	pPos->x_advance = 0.;
 
       pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy += pPos->y_advance;
     }
   }
   else
   {
     curradvx = gr_seg_advance_X(seg) * xscale;
     for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
     {
       if (info->cluster != currclus)
       {
-        pPos->x_advance = info->var1.i32 * xscale;
-        curradvx -= pPos->x_advance;
-        currclus = info->cluster;
+	pPos->x_advance = info->var1.i32 * xscale;
+	curradvx -= pPos->x_advance;
+	currclus = info->cluster;
       } else
-        pPos->x_advance = 0.;
+	pPos->x_advance = 0.;
 
       pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
       curradvy -= pPos->y_advance;
       pPos->x_offset = (gr_slot_origin_X (is) - info->var1.i32) * xscale - curradvx + pPos->x_advance;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
     }
     hb_buffer_reverse_clusters (buffer);
   }
--- a/gfx/harfbuzz/src/hb-graphite2.h
+++ b/gfx/harfbuzz/src/hb-graphite2.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2011  Martin Hosken
- * Copyright (C) 2011  SIL International
+ * Copyright © 2011  Martin Hosken
+ * Copyright © 2011  SIL International
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Permission is hereby granted, without written agreement and without
  * license or royalty fees, to use, copy, modify, and distribute this
  * software and its documentation for any purpose, provided that the
  * above copyright notice and the following two paragraphs appear in
  * all copies of this software.
--- a/gfx/harfbuzz/src/hb-icu.cc
+++ b/gfx/harfbuzz/src/hb-icu.cc
@@ -346,17 +346,22 @@ hb_icu_unicode_decompose_compatibility (
 
 
 static hb_unicode_funcs_t *static_icu_funcs = nullptr;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_icu_funcs (void)
 {
-  hb_unicode_funcs_destroy (static_icu_funcs);
+retry:
+  hb_unicode_funcs_t *icu_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs);
+  if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, icu_funcs, nullptr))
+    goto retry;
+
+  hb_unicode_funcs_destroy (icu_funcs);
 }
 #endif
 
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
 retry:
   hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs);
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-map-private.hh
@@ -0,0 +1,255 @@
+/*
+ * Copyright © 2018  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_MAP_PRIVATE_HH
+#define HB_MAP_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+
+
+template <typename T>
+inline uint32_t Hash (const T &v)
+{
+  /* Knuth's multiplicative method: */
+  return (uint32_t) v * 2654435761u;
+}
+
+
+/*
+ * hb_map_t
+ */
+
+struct hb_map_t
+{
+  struct item_t
+  {
+    hb_codepoint_t key;
+    hb_codepoint_t value;
+
+    inline bool is_unused (void) const { return key == INVALID; }
+    inline bool is_tombstone (void) const { return key != INVALID && value == INVALID; }
+  };
+
+  hb_object_header_t header;
+  bool successful; /* Allocations successful */
+  unsigned int population; /* Not including tombstones. */
+  unsigned int occupancy; /* Including tombstones. */
+  unsigned int mask;
+  unsigned int prime;
+  item_t *items;
+
+  inline void init_shallow (void)
+  {
+    successful = true;
+    population = occupancy = 0;
+    mask = 0;
+    prime = 0;
+    items = nullptr;
+  }
+  inline void init (void)
+  {
+    hb_object_init (this);
+    init_shallow ();
+  }
+  inline void fini_shallow (void)
+  {
+    free (items);
+  }
+  inline void fini (void)
+  {
+    hb_object_fini (this);
+    fini_shallow ();
+  }
+
+  inline bool resize (void)
+  {
+    if (unlikely (!successful)) return false;
+
+    unsigned int power = _hb_bit_storage (population * 2 + 8);
+    unsigned int new_size = 1u << power;
+    item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
+    if (unlikely (!new_items))
+    {
+      successful = false;
+      return false;
+    }
+    memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
+
+    unsigned int old_size = mask + 1;
+    item_t *old_items = items;
+
+    /* Switch to new, empty, array. */
+    population = occupancy = 0;
+    mask = new_size - 1;
+    prime = prime_for (power);
+    items = new_items;
+
+    /* Insert back old items. */
+    if (old_items)
+      for (unsigned int i = 0; i < old_size; i++)
+	if (old_items[i].key != INVALID && old_items[i].value != INVALID)
+	  set (old_items[i].key, old_items[i].value);
+
+    free (old_items);
+
+    return true;
+  }
+
+  inline void set (hb_codepoint_t key, hb_codepoint_t value)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (key == INVALID)) return;
+    if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
+    unsigned int i = bucket_for (key);
+
+    if (value == INVALID && items[i].key != key)
+      return; /* Trying to delete non-existent key. */
+
+    if (!items[i].is_unused ())
+    {
+      occupancy--;
+      if (items[i].is_tombstone ())
+	population--;
+    }
+
+    items[i].key = key;
+    items[i].value = value;
+
+    occupancy++;
+    if (!items[i].is_tombstone ())
+      population++;
+
+  }
+  inline hb_codepoint_t get (hb_codepoint_t key) const
+  {
+    if (unlikely (!items)) return INVALID;
+    unsigned int i = bucket_for (key);
+    return items[i].key == key ? items[i].value : INVALID;
+  }
+
+  inline void del (hb_codepoint_t key)
+  {
+    set (key, INVALID);
+  }
+  inline bool has (hb_codepoint_t key) const
+  {
+    return get (key) != INVALID;
+  }
+
+  inline hb_codepoint_t operator [] (unsigned int key) const
+  { return get (key); }
+
+  static const hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
+
+  inline void clear (void)
+  {
+    memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
+    population = occupancy = 0;
+  }
+
+  inline bool is_empty (void) const
+  {
+    return population != 0;
+  }
+
+  inline unsigned int get_population () const
+  {
+    return population;
+  }
+
+  protected:
+
+  inline unsigned int bucket_for (hb_codepoint_t key) const
+  {
+    unsigned int i = Hash (key) % prime;
+    unsigned int step = 0;
+    unsigned int tombstone = INVALID;
+    while (!items[i].is_unused ())
+    {
+      if (items[i].key == key)
+        return i;
+      if (tombstone == INVALID && items[i].is_tombstone ())
+        tombstone = i;
+      i = (i + ++step) & mask;
+    }
+    return tombstone == INVALID ? i : tombstone;
+  }
+
+  static inline unsigned int prime_for (unsigned int shift)
+  {
+    /* Following comment and table copied from glib. */
+    /* Each table size has an associated prime modulo (the first prime
+     * lower than the table size) used to find the initial bucket. Probing
+     * then works modulo 2^n. The prime modulo is necessary to get a
+     * good distribution with poor hash functions.
+     */
+    /* Not declaring static to make all kinds of compilers happy... */
+    /*static*/ const unsigned int prime_mod [32] =
+    {
+      1,          /* For 1 << 0 */
+      2,
+      3,
+      7,
+      13,
+      31,
+      61,
+      127,
+      251,
+      509,
+      1021,
+      2039,
+      4093,
+      8191,
+      16381,
+      32749,
+      65521,      /* For 1 << 16 */
+      131071,
+      262139,
+      524287,
+      1048573,
+      2097143,
+      4194301,
+      8388593,
+      16777213,
+      33554393,
+      67108859,
+      134217689,
+      268435399,
+      536870909,
+      1073741789,
+      2147483647  /* For 1 << 31 */
+    };
+
+    if (unlikely (shift >= ARRAY_LENGTH (prime_mod)))
+      return prime_mod[ARRAY_LENGTH (prime_mod) - 1];
+
+    return prime_mod[shift];
+  }
+};
+
+
+#endif /* HB_MAP_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-map.cc
@@ -0,0 +1,261 @@
+/*
+ * Copyright © 2018  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-map-private.hh"
+
+
+/* Public API */
+
+
+/**
+ * hb_map_create: (Xconstructor)
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.7.7
+ **/
+hb_map_t *
+hb_map_create (void)
+{
+  hb_map_t *map;
+
+  if (!(map = hb_object_create<hb_map_t> ()))
+    return hb_map_get_empty ();
+
+  map->init_shallow ();
+
+  return map;
+}
+
+/**
+ * hb_map_get_empty:
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.7.7
<