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 812277 4af580347b1c655f23efc2924e96ddd88b0dbaca
parent 812178 2259143ecb07731b4b3c8eca8df5024251ffaf97
child 812278 e82cf1aca043841a96636e9d4be63d03eab80ad9
push id114518
push userbmo:jgilbert@mozilla.com
push dateFri, 29 Jun 2018 00:53:25 +0000
reviewersjfkthame
bugs1467108
milestone63.0a1
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
+ **/
+hb_map_t *
+hb_map_get_empty (void)
+{
+  return const_cast<hb_map_t *> (&Null(hb_map_t));
+}
+
+/**
+ * hb_map_reference: (skip)
+ * @map: a map.
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.7.7
+ **/
+hb_map_t *
+hb_map_reference (hb_map_t *map)
+{
+  return hb_object_reference (map);
+}
+
+/**
+ * hb_map_destroy: (skip)
+ * @map: a map.
+ *
+ * Since: 1.7.7
+ **/
+void
+hb_map_destroy (hb_map_t *map)
+{
+  if (!hb_object_destroy (map)) return;
+
+  map->fini_shallow ();
+
+  free (map);
+}
+
+/**
+ * hb_map_set_user_data: (skip)
+ * @map: a map.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ * Return value:
+ *
+ * Since: 1.7.7
+ **/
+hb_bool_t
+hb_map_set_user_data (hb_map_t           *map,
+		      hb_user_data_key_t *key,
+		      void *              data,
+		      hb_destroy_func_t   destroy,
+		      hb_bool_t           replace)
+{
+  return hb_object_set_user_data (map, key, data, destroy, replace);
+}
+
+/**
+ * hb_map_get_user_data: (skip)
+ * @map: a map.
+ * @key:
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.7.7
+ **/
+void *
+hb_map_get_user_data (hb_map_t           *map,
+		      hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (map, key);
+}
+
+
+/**
+ * hb_map_allocation_successful:
+ * @map: a map.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.7.7
+ **/
+hb_bool_t
+hb_map_allocation_successful (const hb_map_t  *map)
+{
+  return map->successful;
+}
+
+
+/**
+ * hb_map_set:
+ * @map: a map.
+ * @key:
+ * @value:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.7.7
+ **/
+void
+hb_map_set (hb_map_t       *map,
+	    hb_codepoint_t  key,
+	    hb_codepoint_t  value)
+{
+  map->set (key, value);
+}
+
+/**
+ * hb_map_get:
+ * @map: a map.
+ * @key:
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+hb_codepoint_t
+hb_map_get (const hb_map_t *map,
+	    hb_codepoint_t  key)
+{
+  return map->get (key);
+}
+
+/**
+ * hb_map_del:
+ * @map: a map.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+void
+hb_map_del (hb_map_t       *map,
+	    hb_codepoint_t  key)
+{
+  map->del (key);
+}
+
+/**
+ * hb_map_has:
+ * @map: a map.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+hb_bool_t
+hb_map_has (const hb_map_t *map,
+	    hb_codepoint_t  key)
+{
+  return map->has (key);
+}
+
+
+/**
+ * hb_map_clear:
+ * @map: a map.
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+void
+hb_map_clear (hb_map_t *map)
+{
+  return map->clear ();
+}
+
+/**
+ * hb_map_is_empty:
+ * @map: a map.
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+hb_bool_t
+hb_map_is_empty (const hb_map_t *map)
+{
+  return map->is_empty ();
+}
+
+/**
+ * hb_map_get_population:
+ * @map: a map.
+ *
+ *
+ *
+ * Since: 1.7.7
+ **/
+unsigned int
+hb_map_get_population (const hb_map_t *map)
+{