summaryrefslogtreecommitdiff
path: root/libre/icecat
diff options
context:
space:
mode:
Diffstat (limited to 'libre/icecat')
-rw-r--r--libre/icecat/PKGBUILD197
-rw-r--r--libre/icecat/disable-crypto-hardening-settings.patch54
-rw-r--r--libre/icecat/disable-spoofSource-referer.patch26
-rw-r--r--libre/icecat/firefox-gcc-6.0.patch26
-rw-r--r--libre/icecat/gcc6-fix-compilation-for-IceCat.patch37
-rw-r--r--libre/icecat/gnu_headshadow.pngbin0 -> 6785 bytes
-rw-r--r--libre/icecat/harfbuzz-1.1.3.patch27038
-rw-r--r--libre/icecat/icecat-fixed-loading-icon.pngbin0 -> 12184 bytes
-rw-r--r--libre/icecat/icecat-gtk3-20.patch1638
-rw-r--r--libre/icecat/icecat-install-dir.patch12
-rw-r--r--libre/icecat/icecat.desktop352
-rw-r--r--libre/icecat/icecat.install13
-rw-r--r--libre/icecat/libre.patch891
-rw-r--r--libre/icecat/mozconfig48
-rw-r--r--libre/icecat/mozilla-1228540-1.patch84
-rw-r--r--libre/icecat/no-libnotify.patch51
-rw-r--r--libre/icecat/remove-google-play-services-support.patch64
-rw-r--r--libre/icecat/vendor.js28
18 files changed, 30559 insertions, 0 deletions
diff --git a/libre/icecat/PKGBUILD b/libre/icecat/PKGBUILD
new file mode 100644
index 000000000..7e20a485b
--- /dev/null
+++ b/libre/icecat/PKGBUILD
@@ -0,0 +1,197 @@
+# Maintainer: André Silva <emulatorman@parabola.nu>
+# Contributor: Márcio Silva <coadde@parabola.nu>
+# Contributor (ConnochaetOS): Henry Jensen <hjensen@connochaetos.org>
+# Contributor: Luke Shumaker <lukeshu@sbcglobal.net>
+# Contributor: fauno <fauno@kiwwwi.com.ar>
+# Contributor: vando <facundo@esdebian.org>
+# Contributor (Arch): Jakub Schmidtke <sjakub@gmail.com>
+# Contributor: Figue <ffigue at gmail>
+# Thank you very much to the older contributors:
+# Contributor: evr <evanroman at gmail>
+# Contributor: Muhammad 'MJ' Jassim <UnbreakableMJ@gmail.com>
+
+_pgo=false
+
+pkgname=icecat
+_pkgver=45.5.1-gnu1
+pkgver=${_pkgver//-/_}
+pkgrel=1
+
+pkgdesc="GNU IceCat, the standalone web browser based on Mozilla Firefox."
+arch=(i686 x86_64)
+license=(MPL GPL LGPL)
+depends=(alsa-lib dbus-glib desktop-file-utils ffmpeg gtk2 gtk3 hicolor-icon-theme hunspell icu=58.1 libevent libvpx=1.6.0 libxt mime-types mozilla-common nss sqlite startup-notification ttf-font)
+makedepends=(diffutils gconf imake inetutils libpulse mesa mozilla-searchplugins python2 unzip yasm zip)
+options=(!emptydirs !makeflags debug)
+if $_pgo; then
+ makedepends+=(xorg-server-xvfb)
+ options+=(!ccache)
+fi
+optdepends=('networkmanager: Location detection via available WiFi networks'
+ 'upower: Battery API')
+url="http://www.gnu.org/software/gnuzilla/"
+install=$pkgname.install
+source=(http://ftp.gnu.org/gnu/gnuzilla/${_pkgver%-*}/$pkgname-$_pkgver.tar.bz2{,.sig}
+#mksource=(http://jenkins.trisquel.info/$pkgname/$pkgname-$_pkgver.tar.bz2)
+#source=(https://repo.parabola.nu/other/$pkgname/$pkgname-$_pkgver.tar.bz2{,.sig}
+ mozconfig
+ libre.patch
+ gnu_headshadow.png
+ $pkgname.desktop
+ $pkgname-install-dir.patch
+ firefox-gcc-6.0.patch
+ gcc6-fix-compilation-for-IceCat.patch
+ mozilla-1228540-1.patch
+ vendor.js
+ $pkgname-fixed-loading-icon.png
+ no-libnotify.patch
+ $pkgname-gtk3-20.patch
+ disable-crypto-hardening-settings.patch
+ disable-spoofSource-referer.patch)
+sha256sums=('8163e5bc53f69d9f9b0fc5e9f95fae33da8139ae0f902756751cadbaa27e6ee9'
+ 'SKIP'
+ '89f375161a085ec37e88d5ceb9562dc33ed8ef03e225fefa819dfe3c6eb7290f'
+ '583fe7b1897a7437854415c33cedefed1c987ca2ffea6b5826a99d4e7a71e05f'
+ '93e3001ce152e1d142619e215a9ef07dd429943b99d21726c25da9ceb31e31cd'
+ '52df9ffeb52166ed4abd9a132ee4a9017b9c4980f0725ba383610ccfb06d4745'
+ '5bdab2de5520fb4d3dbc453d9f73d20e0e077bf652bc780fc17184ba6c718a47'
+ '4d1e1ddabc9e975ed39f49e134559a29e01cd49439e358233f1ede43bf5a52bf'
+ '329cf6753d29ae64a4336a8a76ee71f0d331a39132159401e4d11de65b708a07'
+ 'd1ccbaf0973615c57f7893355e5cd3a89efb4e91071d0ec376e429b50cf6ed19'
+ '977aa49b940f1da049cefa2878a63ac6669a78e63e9d55bb11db7b8f8fb64c33'
+ '68e3a5b47c6d175cc95b98b069a15205f027cab83af9e075818d38610feb6213'
+ 'e4ebdd14096d177d264a7993dbd5df46463605ff45f783732c26d30b9caa53a7'
+ '2e355a477f1df792cd7f9d1e3a56030543e0cf2d09051dd293ba495a7edb54fd'
+ '0166aa368420f0bf0aab064b2188e3d852b241efeeb27dee66df2bc15e84b83a'
+ 'c50043266e69f5844e6dce9ea7193af79587dcaa66806932d7867281a176f03e')
+validpgpkeys=(
+ 'A57369A8BABC2542B5A0368C3C76EED7D7E04784' # Ruben Rodriguez
+)
+
+prepare() {
+ export GNU_BUILD="gnuzilla-release"
+
+ mv $pkgname-${pkgver%_*} "$srcdir/$GNU_BUILD"
+ cd "$srcdir/$GNU_BUILD"
+
+ # Put gnu_headshadow.png in the source code
+ install -m644 "$srcdir/gnu_headshadow.png" \
+ browser/base/content/abouthome
+
+ # Install to /usr/lib/$pkgname
+ patch -Np1 -i "$srcdir/$pkgname-install-dir.patch"
+
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1234158
+ patch -Np1 -i "$srcdir/$pkgname-gtk3-20.patch"
+
+ # Notifications with libnotify are broken
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1236150
+ patch -Np1 -i "$srcdir/no-libnotify.patch"
+
+ # Compilation fix (FS#49243 and FS#49363), internet and Icedove package
+ patch -Np1 -i $srcdir/gcc6-fix-compilation-for-IceCat.patch
+ patch -Np1 -i $srcdir/firefox-gcc-6.0.patch
+
+ # Update to harfbuzz (following Icedove in [libre])
+ patch -Np1 -i $srcdir/mozilla-1228540-1.patch
+
+ # Patch and remove anything that's left
+ patch -Np1 -i "$srcdir/libre.patch"
+ rm -v browser/base/content/abouthome/snippet*.png || true
+ sed -i '\|abouthome/snippet|d
+ ' browser/base/jar.mn
+
+ # Load our build config, disable SafeSearch
+ cp "$srcdir/mozconfig" .mozconfig
+
+ mkdir "$srcdir/path"
+
+ # WebRTC build tries to execute "python" and expects Python 2
+ ln -s /usr/bin/python2 "$srcdir/path/python"
+
+ # Configure script misdetects the preprocessor without an optimization level
+ # https://bugs.archlinux.org/task/34644
+ sed -i '/ac_cpp=/s/$CPPFLAGS/& -O2/' configure
+
+ # Fix tab loading icon (doesn't work with libpng 1.6)
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=841734
+ cp "$srcdir/$pkgname-fixed-loading-icon.png" \
+ browser/themes/linux/tabbrowser/loading.png
+
+ # Load our searchplugins
+ rm -rv browser/locales/en-US/searchplugins
+ cp -av /usr/lib/mozilla/searchplugins browser/locales/en-US
+
+ # Disable crypto hardening settings for now
+ # https://lists.parabola.nu/pipermail/assist/2015-October/000534.html
+ # https://labs.parabola.nu/issues/842
+ patch -Np1 -i "$srcdir/disable-crypto-hardening-settings.patch"
+
+ # Disable spoofSource referer since it breaks referer function used by some sites
+ # https://labs.parabola.nu/issues/1073
+ patch -Np1 -i "$srcdir/disable-spoofSource-referer.patch"
+}
+
+build() {
+ export GNU_BUILD="gnuzilla-release"
+
+ cd "$srcdir/$GNU_BUILD"
+
+ # _FORTIFY_SOURCE causes configure failures
+ CPPFLAGS+=" -O2"
+
+ # Hardening
+ LDFLAGS+=" -Wl,-z,now"
+
+ # GCC 6
+ CFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse -fno-schedule-insns2"
+ CXXFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse -fno-schedule-insns2"
+
+ export PATH="$srcdir/path:$PATH"
+ export PYTHON="/usr/bin/python2"
+
+ if $_pgo; then
+ # Do PGO
+ xvfb-run -a -s "-extension GLX -screen 0 1280x1024x24" \
+ make -f client.mk build MOZ_PGO=1
+ else
+ make -f client.mk build
+ fi
+}
+
+package() {
+ export GNU_BUILD="gnuzilla-release"
+
+ cd "$srcdir/$GNU_BUILD"
+ make -f client.mk DESTDIR="$pkgdir" INSTALL_SDK= install
+
+ install -Dm644 ../vendor.js "$pkgdir/usr/lib/$pkgname/browser/defaults/preferences/vendor.js"
+
+ brandingdir=browser/branding/official
+ icondir="$pkgdir/usr/share/icons/hicolor"
+ for i in 16 22 24 32 48 256; do
+ install -Dm644 "$brandingdir/default$i.png" \
+ "$icondir/${i}x${i}/apps/$pkgname.png"
+ done
+ install -Dm644 "$brandingdir/content/icon64.png" \
+ "$icondir/64x64/apps/$pkgname.png"
+ install -Dm644 "$brandingdir/mozicon128.png" \
+ "$icondir/128x128/apps/$pkgname.png"
+ install -Dm644 "$brandingdir/content/about-logo.png" \
+ "$icondir/192x192/apps/$pkgname.png"
+ install -Dm644 "$brandingdir/content/about-logo@2x.png" \
+ "$icondir/384x384/apps/$pkgname.png"
+
+ install -d "$pkgdir/usr/share/applications"
+ install -m644 "$srcdir/$pkgname.desktop" \
+ "$pkgdir/usr/share/applications"
+
+ # Use system-provided dictionaries
+ rm -rf "$pkgdir/usr/lib/$pkgname/"{dictionaries,hyphenation}
+ ln -s /usr/share/hunspell "$pkgdir/usr/lib/$pkgname/dictionaries"
+ ln -s /usr/share/hyphen "$pkgdir/usr/lib/$pkgname/hyphenation"
+
+ # Replace duplicate binary with symlink
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=658850
+ ln -sf $pkgname "$pkgdir/usr/lib/$pkgname/$pkgname-bin"
+}
diff --git a/libre/icecat/disable-crypto-hardening-settings.patch b/libre/icecat/disable-crypto-hardening-settings.patch
new file mode 100644
index 000000000..3c7dedd77
--- /dev/null
+++ b/libre/icecat/disable-crypto-hardening-settings.patch
@@ -0,0 +1,54 @@
+diff --git a/browser/app/profile/icecat.js b/browser/app/profile/icecat.js
+index 3308a22..6b81444 100644
+--- a/browser/app/profile/icecat.js
++++ b/browser/app/profile/icecat.js
+@@ -2035,14 +2035,14 @@ pref("network.http.speculative-parallel-limit", 0);
+ // Crypto hardening
+ // https://gist.github.com/haasn/69e19fc2fe0e25f3cff5
+ //General settings
+-pref("security.tls.unrestricted_rc4_fallback", false);
+-pref("security.tls.insecure_fallback_hosts.use_static_list", false);
+-pref("security.tls.version.min", 1);
+-pref("security.ssl.require_safe_negotiation", true);
+-pref("security.ssl.treat_unsafe_negotiation_as_broken", true);
+-pref("security.ssl3.rsa_seed_sha", true);
+-pref("security.OCSP.enabled", 1);
+-pref("security.OCSP.require", true);
++//pref("security.tls.unrestricted_rc4_fallback", false);
++//pref("security.tls.insecure_fallback_hosts.use_static_list", false);
++//pref("security.tls.version.min", 1);
++//pref("security.ssl.require_safe_negotiation", true);
++//pref("security.ssl.treat_unsafe_negotiation_as_broken", true);
++//pref("security.ssl3.rsa_seed_sha", true);
++//pref("security.OCSP.enabled", 1);
++//pref("security.OCSP.require", true);
+
+ // Disable channel updates
+ pref("app.update.enabled", false);
+diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
+index bfc6cba..cfdeb22 100644
+--- a/mobile/android/app/mobile.js
++++ b/mobile/android/app/mobile.js
+@@ -997,14 +997,14 @@ pref("network.http.speculative-parallel-limit", 0);
+ // Crypto hardening
+ // https://gist.github.com/haasn/69e19fc2fe0e25f3cff5
+ //General settings
+-pref("security.tls.unrestricted_rc4_fallback", false);
+-pref("security.tls.insecure_fallback_hosts.use_static_list", false);
+-pref("security.tls.version.min", 1);
+-pref("security.ssl.require_safe_negotiation", true);
+-pref("security.ssl.treat_unsafe_negotiation_as_broken", true);
+-pref("security.ssl3.rsa_seed_sha", true);
+-pref("security.OCSP.enabled", 1);
+-pref("security.OCSP.require", true);
++//pref("security.tls.unrestricted_rc4_fallback", false);
++//pref("security.tls.insecure_fallback_hosts.use_static_list", false);
++//pref("security.tls.version.min", 1);
++//pref("security.ssl.require_safe_negotiation", true);
++//pref("security.ssl.treat_unsafe_negotiation_as_broken", true);
++//pref("security.ssl3.rsa_seed_sha", true);
++//pref("security.OCSP.enabled", 1);
++//pref("security.OCSP.require", true);
+
+ // Disable channel updates
+ pref("app.update.enabled", false);
diff --git a/libre/icecat/disable-spoofSource-referer.patch b/libre/icecat/disable-spoofSource-referer.patch
new file mode 100644
index 000000000..d239b02f1
--- /dev/null
+++ b/libre/icecat/disable-spoofSource-referer.patch
@@ -0,0 +1,26 @@
+diff --git a/browser/app/profile/icecat.js b/browser/app/profile/icecat.js
+index 6b81444..42dd5ed 100644
+--- a/browser/app/profile/icecat.js
++++ b/browser/app/profile/icecat.js
+@@ -2011,7 +2011,7 @@ pref("datareporting.policy.dataSubmissionEnabled", false);
+ pref("datareporting.healthreport.service.enabled", false);
+ pref("browser.slowStartup.notificationDisabled", true);
+ pref("network.http.sendRefererHeader", 2);
+-pref("network.http.referer.spoofSource", true);
++//pref("network.http.referer.spoofSource", true);
+ //http://grack.com/blog/2010/01/06/3rd-party-cookies-dom-storage-and-privacy/
+ //pref("dom.storage.enabled", false);
+ pref("dom.event.clipboardevents.enabled",false);
+diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
+index cfdeb22..f5845d4 100644
+--- a/mobile/android/app/mobile.js
++++ b/mobile/android/app/mobile.js
+@@ -973,7 +973,7 @@ pref("datareporting.policy.dataSubmissionEnabled", false);
+ pref("datareporting.healthreport.service.enabled", false);
+ pref("browser.slowStartup.notificationDisabled", true);
+ pref("network.http.sendRefererHeader", 2);
+-pref("network.http.referer.spoofSource", true);
++//pref("network.http.referer.spoofSource", true);
+ //http://grack.com/blog/2010/01/06/3rd-party-cookies-dom-storage-and-privacy/
+ //pref("dom.storage.enabled", false);
+ pref("dom.event.clipboardevents.enabled",false);
diff --git a/libre/icecat/firefox-gcc-6.0.patch b/libre/icecat/firefox-gcc-6.0.patch
new file mode 100644
index 000000000..0a74d3616
--- /dev/null
+++ b/libre/icecat/firefox-gcc-6.0.patch
@@ -0,0 +1,26 @@
+diff -up firefox-44.0/nsprpub/config/make-system-wrappers.pl.back firefox-44.0/nsprpub/config/make-system-wrappers.pl
+--- firefox-44.0/nsprpub/config/make-system-wrappers.pl.back 2016-01-24 00:23:49.000000000 +0100
++++ firefox-44.0/nsprpub/config/make-system-wrappers.pl 2016-02-02 14:58:45.064112655 +0100
+@@ -19,7 +19,9 @@ while (<STDIN>) {
+ open OUT, ">$output_dir/$_";
+ print OUT "#pragma GCC system_header\n"; # suppress include_next warning
+ print OUT "#pragma GCC visibility push(default)\n";
++ print OUT "#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS\n";
+ print OUT "#include_next \<$_\>\n";
++ print OUT "#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS\n";
+ print OUT "#pragma GCC visibility pop\n";
+ close OUT;
+ }
+diff -up firefox-44.0/mozglue/build/arm.cpp.old firefox-44.0/mozglue/build/arm.cpp
+--- firefox-44.0/mozglue/build/arm.cpp.old 2016-02-03 10:07:29.879526500 +0100
++++ firefox-44.0/mozglue/build/arm.cpp 2016-02-03 10:08:11.062697517 +0100
+@@ -104,7 +104,9 @@ check_neon(void)
+
+ # elif defined(__linux__) || defined(ANDROID)
+ # include <stdio.h>
++#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+ # include <stdlib.h>
++#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+ # include <string.h>
+
+ enum{
diff --git a/libre/icecat/gcc6-fix-compilation-for-IceCat.patch b/libre/icecat/gcc6-fix-compilation-for-IceCat.patch
new file mode 100644
index 000000000..2c291567c
--- /dev/null
+++ b/libre/icecat/gcc6-fix-compilation-for-IceCat.patch
@@ -0,0 +1,37 @@
+--- a/config/gcc-stl-wrapper.template.h 2016-05-10 22:26:46.000000000 +0200
++++ b/config/gcc-stl-wrapper.template.h 2016-05-23 23:48:21.137431360 +0200
+@@ -22,6 +22,11 @@
+ #define NOMINMAX 1
+ #endif
+
++// Don't include mozalloc for cstdlib. See bug 1245076.
++#ifndef moz_dont_include_mozalloc_for_cstdlib
++# define moz_dont_include_mozalloc_for_cstdlib
++#endif
++#ifndef moz_dont_include_mozalloc_for_${HEADER}
+ // mozalloc.h wants <new>; break the cycle by always explicitly
+ // including <new> here. NB: this is a tad sneaky. Sez the gcc docs:
+ //
+@@ -30,15 +35,17 @@
+ // same name as the current file. It simply looks for the file
+ // named, starting with the directory in the search path after the
+ // one where the current file was found.
+-#include_next <new>
++# include_next <new>
+
+ // See if we're in code that can use mozalloc. NB: this duplicates
+ // code in nscore.h because nscore.h pulls in prtypes.h, and chromium
+ // can't build with that being included before base/basictypes.h.
+-#if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
+-# include "mozilla/mozalloc.h"
+-#else
+-# error "STL code can only be used with infallible ::operator new()"
++# if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
++# include "mozilla/mozalloc.h"
++# else
++# error "STL code can only be used with infallible ::operator new()"
++# endif
++
+ #endif
+
+ #if defined(DEBUG) && !defined(_GLIBCXX_DEBUG)
diff --git a/libre/icecat/gnu_headshadow.png b/libre/icecat/gnu_headshadow.png
new file mode 100644
index 000000000..e0f73a3bf
--- /dev/null
+++ b/libre/icecat/gnu_headshadow.png
Binary files differ
diff --git a/libre/icecat/harfbuzz-1.1.3.patch b/libre/icecat/harfbuzz-1.1.3.patch
new file mode 100644
index 000000000..98e25914d
--- /dev/null
+++ b/libre/icecat/harfbuzz-1.1.3.patch
@@ -0,0 +1,27038 @@
+diff -uN gfx/harfbuzz/src_old/check-defs.sh gfx/harfbuzz/src/check-defs.sh
+--- gfx/harfbuzz/src_old/check-defs.sh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/check-defs.sh 2016-06-05 23:47:59.650463392 +0200
+@@ -0,0 +1,44 @@
++#!/bin/sh
++
++LC_ALL=C
++export LC_ALL
++
++test -z "$srcdir" && srcdir=.
++test -z "$MAKE" && MAKE=make
++stat=0
++
++if which nm 2>/dev/null >/dev/null; then
++ :
++else
++ echo "check-defs.sh: 'nm' not found; skipping test"
++ exit 77
++fi
++
++defs="harfbuzz.def"
++$MAKE $defs > /dev/null
++tested=false
++for def in $defs; do
++ lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
++ so=.libs/lib${lib}.so
++
++ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
++
++ if test -f "$so"; then
++
++ echo "Checking that $so has the same symbol list as $def"
++ {
++ echo EXPORTS
++ echo "$EXPORTED_SYMBOLS"
++ # cheat: copy the last line from the def file!
++ tail -n1 "$def"
++ } | diff "$def" - >&2 || stat=1
++
++ tested=true
++ fi
++done
++if ! $tested; then
++ echo "check-defs.sh: libharfbuzz shared library not found; skipping test"
++ exit 77
++fi
++
++exit $stat
+diff -uN gfx/harfbuzz/src_old/check-header-guards.sh gfx/harfbuzz/src/check-header-guards.sh
+--- gfx/harfbuzz/src_old/check-header-guards.sh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/check-header-guards.sh 2016-06-05 23:48:00.885456341 +0200
+@@ -9,13 +9,12 @@
+ test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+ test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
+
+-
+ for x in $HBHEADERS $HBSOURCES; do
+ test -f "$srcdir/$x" && x="$srcdir/$x"
+- echo "$x" | grep '[^h]$' -q && continue;
++ echo "$x" | grep -q '[^h]$' && continue;
+ xx=`echo "$x" | sed 's@.*/@@'`
+ tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
+- lines=`grep "\<$tag\>" "$x" | wc -l | sed 's/[ ]*//g'`
++ lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ ]*//g'`
+ if test "x$lines" != x3; then
+ echo "Ouch, header file $x does not have correct preprocessor guards"
+ stat=1
+diff -uN gfx/harfbuzz/src_old/check-libstdc++.sh gfx/harfbuzz/src/check-libstdc++.sh
+--- gfx/harfbuzz/src_old/check-libstdc++.sh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/check-libstdc++.sh 2016-06-05 23:48:03.413441951 +0200
+@@ -19,9 +19,9 @@
+ so=.libs/libharfbuzz.$suffix
+ if ! test -f "$so"; then continue; fi
+
+- echo "Checking that we are not linking to libstdc++"
+- if ldd $so | grep 'libstdc[+][+]'; then
+- echo "Ouch, linked to libstdc++"
++ echo "Checking that we are not linking to libstdc++ or libc++"
++ if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then
++ echo "Ouch, linked to libstdc++ or libc++"
+ stat=1
+ fi
+ tested=true
+diff -uN gfx/harfbuzz/src_old/gen-indic-table.py gfx/harfbuzz/src/gen-indic-table.py
+--- gfx/harfbuzz/src_old/gen-indic-table.py 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/gen-indic-table.py 2016-06-05 23:48:08.239414549 +0200
+@@ -91,6 +91,7 @@
+ "Visarga": 'Vs',
+ "Vowel": 'Vo',
+ "Vowel_Dependent": 'M',
++ "Consonant_Prefixed": 'CPrf',
+ "Other": 'x',
+ },{
+ "Not_Applicable": 'x',
+@@ -209,7 +210,7 @@
+ 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 (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
++ print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
+ 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]])
+diff -uN gfx/harfbuzz/src_old/gen-use-table.py gfx/harfbuzz/src/gen-use-table.py
+--- gfx/harfbuzz/src_old/gen-use-table.py 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/gen-use-table.py 2016-06-05 23:48:09.467407592 +0200
+@@ -0,0 +1,476 @@
++#!/usr/bin/python
++
++import sys
++
++if len (sys.argv) != 5:
++ print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
++ sys.exit (1)
++
++BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
++
++files = [file (x) 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:
++
++ j = line.find ('#')
++ if j >= 0:
++ line = line[:j]
++
++ fields = [x.strip () for x in line.split (';')]
++ if len (fields) == 1:
++ continue
++
++ uu = fields[0].split ('..')
++ start = int (uu[0], 16)
++ if len (uu) == 1:
++ end = start
++ else:
++ end = int (uu[1], 16)
++
++ t = fields[1 if i != 2 else 2]
++
++ for u in range (start, end + 1):
++ data[i][u] = t
++ values[i][t] = values[i].get (t, 0) + end - start + 1
++
++defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
++
++# TODO Characters that are not in Unicode Indic files, but used in USE
++data[0][0x034F] = defaults[0]
++data[0][0x2060] = defaults[0]
++for u in range (0xFE00, 0xFE0F + 1):
++ data[0][u] = defaults[0]
++
++# Merge data into one dict:
++for i,v in enumerate (defaults):
++ values[i][v] = values[i].get (v, 0) + 1
++combined = {}
++for i,d in enumerate (data):
++ for u,v in d.items ():
++ if i >= 2 and not u in combined:
++ continue
++ if not u in combined:
++ combined[u] = list (defaults)
++ combined[u][i] = v
++combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS}
++data = combined
++del combined
++num = len (data)
++
++
++property_names = [
++ # General_Category
++ 'Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc',
++ 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', 'Pi', 'Po',
++ 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',
++ # Indic_Syllabic_Category
++ 'Other',
++ 'Bindu',
++ 'Visarga',
++ 'Avagraha',
++ 'Nukta',
++ 'Virama',
++ 'Pure_Killer',
++ 'Invisible_Stacker',
++ 'Vowel_Independent',
++ 'Vowel_Dependent',
++ 'Vowel',
++ 'Consonant_Placeholder',
++ 'Consonant',
++ 'Consonant_Dead',
++ 'Consonant_With_Stacker',
++ 'Consonant_Prefixed',
++ 'Consonant_Preceding_Repha',
++ 'Consonant_Succeeding_Repha',
++ 'Consonant_Subjoined',
++ 'Consonant_Medial',
++ 'Consonant_Final',
++ 'Consonant_Head_Letter',
++ 'Modifying_Letter',
++ 'Tone_Letter',
++ 'Tone_Mark',
++ 'Gemination_Mark',
++ 'Cantillation_Mark',
++ 'Register_Shifter',
++ 'Syllable_Modifier',
++ 'Consonant_Killer',
++ 'Non_Joiner',
++ 'Joiner',
++ 'Number_Joiner',
++ 'Number',
++ 'Brahmi_Joining_Number',
++ # Indic_Positional_Category
++ 'Not_Applicable',
++ 'Right',
++ 'Left',
++ 'Visual_Order_Left',
++ 'Left_And_Right',
++ 'Top',
++ 'Bottom',
++ 'Top_And_Bottom',
++ 'Top_And_Right',
++ 'Top_And_Left',
++ 'Top_And_Left_And_Right',
++ 'Bottom_And_Right',
++ 'Top_And_Bottom_And_Right',
++ 'Overstruck',
++]
++
++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)
++
++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
++globals().update(property_values)
++
++
++def is_BASE(U, UISC, UGC):
++ return (UISC in [Number, Consonant, Consonant_Head_Letter,
++ #SPEC-OUTDATED Consonant_Placeholder,
++ Tone_Letter] or
++ (UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial,
++ Consonant_Subjoined, Vowel, Vowel_Dependent]))
++def is_BASE_VOWEL(U, UISC, UGC):
++ return UISC == Vowel_Independent
++def is_BASE_IND(U, UISC, UGC):
++ #SPEC-BROKEN return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
++ return (UISC in [Consonant_Dead, Modifying_Letter] or
++ (UGC == Po and not is_BASE_OTHER(U, UISC, UGC))) # for 104E
++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-OUTDATED
++ return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC,
++ 0x25FB, 0x25FC, 0x25FD, 0x25FE]
++def is_CGJ(U, UISC, UGC):
++ return U == 0x034F
++def is_CONS_FINAL(U, UISC, UGC):
++ return ((UISC == Consonant_Final and UGC != Lo) or
++ UISC == Consonant_Succeeding_Repha)
++def is_CONS_FINAL_MOD(U, UISC, UGC):
++ #SPEC-OUTDATED 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]
++def is_CONS_SUB(U, UISC, UGC):
++ #SPEC-OUTDATED return UISC == Consonant_Subjoined
++ return UISC == Consonant_Subjoined and UGC != Lo
++def is_HALANT(U, UISC, UGC):
++ return UISC in [Virama, Invisible_Stacker]
++def is_HALANT_NUM(U, UISC, UGC):
++ return UISC == Number_Joiner
++def is_ZWNJ(U, UISC, UGC):
++ return UISC == Non_Joiner
++def is_ZWJ(U, UISC, UGC):
++ return UISC == Joiner
++def is_Word_Joiner(U, UISC, UGC):
++ return U == 0x2060
++def is_OTHER(U, UISC, UGC):
++ #SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
++ return (UISC == Other
++ and not is_SYM_MOD(U, UISC, UGC)
++ and not is_CGJ(U, UISC, UGC)
++ and not is_Word_Joiner(U, UISC, UGC)
++ and not is_VARIATION_SELECTOR(U, UISC, UGC)
++ )
++def is_Reserved(U, UISC, UGC):
++ return UGC == 'Cn'
++def is_REPHA(U, UISC, UGC):
++ #return UISC == Consonant_Preceding_Repha
++ #SPEC-OUTDATED hack to categorize Consonant_With_Stacker and Consonant_Prefixed
++ return UISC in [Consonant_Preceding_Repha, Consonant_With_Stacker, Consonant_Prefixed]
++def is_SYM(U, UISC, UGC):
++ if U == 0x25CC: return False #SPEC-OUTDATED
++ #SPEC-OUTDATED return UGC in [So, Sc] or UISC == Symbol_Letter
++ return UGC in [So, Sc]
++def is_SYM_MOD(U, UISC, UGC):
++ return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
++def is_VARIATION_SELECTOR(U, UISC, UGC):
++ return 0xFE00 <= U <= 0xFE0F
++def is_VOWEL(U, UISC, UGC):
++ return (UISC == Pure_Killer or
++ (UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
++def is_VOWEL_MOD(U, UISC, UGC):
++ return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
++ (UGC != Lo and UISC == Bindu))
++
++use_mapping = {
++ 'B': is_BASE,
++ 'IV': is_BASE_VOWEL,
++ 'IND': is_BASE_IND,
++ 'N': is_BASE_NUM,
++ 'GB': is_BASE_OTHER,
++ 'CGJ': is_CGJ,
++ 'F': is_CONS_FINAL,
++ 'FM': is_CONS_FINAL_MOD,
++ 'M': is_CONS_MED,
++ 'CM': is_CONS_MOD,
++ 'SUB': is_CONS_SUB,
++ 'H': is_HALANT,
++ 'HN': is_HALANT_NUM,
++ 'ZWNJ': is_ZWNJ,
++ 'ZWJ': is_ZWJ,
++ 'WJ': is_Word_Joiner,
++ 'O': is_OTHER,
++ 'Rsv': is_Reserved,
++ 'R': is_REPHA,
++ 'S': is_SYM,
++ 'SM': is_SYM_MOD,
++ 'VS': is_VARIATION_SELECTOR,
++ 'V': is_VOWEL,
++ 'VM': is_VOWEL_MOD,
++}
++
++use_positions = {
++ 'F': {
++ 'Abv': [Top],
++ 'Blw': [Bottom],
++ 'Pst': [Right],
++ },
++ 'M': {
++ 'Abv': [Top],
++ 'Blw': [Bottom],
++ 'Pst': [Right],
++ 'Pre': [Left],
++ },
++ 'CM': {
++ 'Abv': [Top],
++ 'Blw': [Bottom],
++ },
++ 'V': {
++ 'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
++ 'Blw': [Bottom, Overstruck, Bottom_And_Right],
++ 'Pst': [Right],
++ 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
++ },
++ 'VM': {
++ 'Abv': [Top],
++ 'Blw': [Bottom, Overstruck],
++ 'Pst': [Right],
++ 'Pre': [Left],
++ },
++ 'SM': {
++ 'Abv': [Top],
++ 'Blw': [Bottom],
++ },
++ 'H': None,
++ 'B': None,
++ 'FM': None,
++ 'SUB': None,
++}
++
++def map_to_use(data):
++ out = {}
++ items = use_mapping.items()
++ for U,(UISC,UIPC,UGC,UBlock) in data.items():
++
++ # Resolve Indic_Syllabic_Category
++
++ # TODO: These don't have UISC assigned in Unicode 8.0, but
++ # have UIPC
++ if U == 0x17DD: UISC = Vowel_Dependent
++ if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
++
++ # TODO: U+1CED should only be allowed after some of
++ # the nasalization marks, maybe only for U+1CE9..U+1CF1.
++ if U == 0x1CED: UISC = Tone_Mark
++
++ evals = [(k, v(U,UISC,UGC)) for k,v in items]
++ values = [k for k,v in evals if v]
++ assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
++ USE = values[0]
++
++ # 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
++ if U == 0x103C: UIPC = Left
++
++ # TODO: These are not in USE's override list that we have, nor are they in Unicode 8.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
++
++ 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)
++
++# Remove the outliers
++singles = {}
++for u in [0x034F, 0x25CC, 0x1107F]:
++ singles[u] = data[u]
++ del data[u]
++
++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
++
++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
++ if start % 16:
++ print ' ' * (20 + (start % 16 * 6)),
++ 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,
++ if u in data:
++ num += 1
++ d = data.get (u, defaults)
++ sys.stdout.write ("%6s," % d[0])
++
++ total += end - start + 1
++ used += num
++ if block:
++ last_block = block
++
++uu = data.keys ()
++uu.sort ()
++
++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:])
++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[] = {"
++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]:
++ end += 1
++ end = (end-1)//8*8 + 7
++
++ 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)
++ starts.append (start)
++
++ print_block (block, start, end, data)
++ last = end
++ends.append (last + 1)
++offset += ends[-1] - starts[-1]
++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_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()])
++for p in sorted(pages):
++ 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 (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
++ for u,d in singles.items ():
++ if p != u>>page_bits: continue
++ print " if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])
++ 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
++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 == */"
++
++# Maintain at least 50% occupancy in the table */
++if occupancy < 50:
++ raise Exception ("Table too sparse, please investigate: ", occupancy)
+diff -uN gfx/harfbuzz/src_old/harfbuzz-icu.pc gfx/harfbuzz/src/harfbuzz-icu.pc
+--- gfx/harfbuzz/src_old/harfbuzz-icu.pc 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/harfbuzz-icu.pc 2016-06-05 23:48:12.049392976 +0200
+@@ -0,0 +1,13 @@
++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.0.1
++
++Requires: harfbuzz
++Requires.private: icu-uc
++Libs: -L${libdir} -lharfbuzz-icu
++Cflags: -I${includedir}/harfbuzz
+diff -uN gfx/harfbuzz/src_old/harfbuzz.pc gfx/harfbuzz/src/harfbuzz.pc
+--- gfx/harfbuzz/src_old/harfbuzz.pc 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/harfbuzz.pc 2016-06-05 23:48:14.499379160 +0200
+@@ -0,0 +1,11 @@
++prefix=/usr/local
++exec_prefix=/usr/local
++libdir=/usr/local/lib
++includedir=/usr/local/include
++
++Name: harfbuzz
++Description: HarfBuzz text shaping library
++Version: 1.0.1
++
++Libs: -L${libdir} -lharfbuzz
++Cflags: -I${includedir}/harfbuzz
+diff -uN gfx/harfbuzz/src_old/harfbuzz.pc.in gfx/harfbuzz/src/harfbuzz.pc.in
+--- gfx/harfbuzz/src_old/harfbuzz.pc.in 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/harfbuzz.pc.in 2016-06-05 23:48:15.731372204 +0200
+@@ -8,4 +8,6 @@
+ Version: %VERSION%
+
+ Libs: -L${libdir} -lharfbuzz
++Libs.private: %libs_private%
++Requires.private: %requires_private%
+ Cflags: -I${includedir}/harfbuzz
+diff -uN gfx/harfbuzz/src_old/hb-atomic-private.hh gfx/harfbuzz/src/hb-atomic-private.hh
+--- gfx/harfbuzz/src_old/hb-atomic-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-atomic-private.hh 2016-06-05 23:48:16.918365513 +0200
+@@ -39,7 +39,11 @@
+
+ /* We need external help for these */
+
+-#if 0
++#if defined(hb_atomic_int_impl_add) \
++ && defined(hb_atomic_ptr_impl_get) \
++ && defined(hb_atomic_ptr_impl_cmpexch)
++
++/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
+
+
+ #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
+@@ -58,11 +62,12 @@
+ #endif
+ }
+
+-typedef LONG hb_atomic_int_t;
+-#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
++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_get(P) (_HBMemoryBarrier (), (void *) *(P))
+-#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
++#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(__APPLE__)
+@@ -74,28 +79,31 @@
+ #include <Availability.h>
+ #endif
+
+-typedef int32_t hb_atomic_int_t;
+-#define hb_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
+
+-#define hb_atomic_ptr_get(P) (OSMemoryBarrier (), (void *) *(P))
++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_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
++#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_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
++#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+ #else
+-#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
++#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+ #endif
+ #endif
+
+
+ #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
+
+-typedef int hb_atomic_int_t;
+-#define hb_atomic_int_add(AI, V) __sync_fetch_and_add (&(AI), (V))
++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_get(P) (void *) (__sync_synchronize (), *(P))
+-#define hb_atomic_ptr_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
++#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)
+@@ -103,33 +111,79 @@
+ #include <atomic.h>
+ #include <mbarrier.h>
+
+-typedef unsigned int hb_atomic_int_t;
+-#define hb_atomic_int_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
++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(_AIX) && defined(__IBMCPP__)
++
++#include <builtins.h>
++
++
++static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
++ __lwsync();
++ int result = __fetch_and_add(AI, V);
++ __isync();
++ return result;
++}
++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;
++}
+
+-#define hb_atomic_ptr_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P))
+-#define hb_atomic_ptr_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
++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_t;
+-#define hb_atomic_int_add(AI, V) (((AI) += (V)) - (V))
+
+-#define hb_atomic_ptr_get(P) ((void *) *(P))
+-#define hb_atomic_ptr_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
++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_t;
+-#define hb_atomic_int_add(AI, V) (((AI) += (V)) - (V))
++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)
+
+-#define hb_atomic_ptr_get(P) ((void *) *(P))
+-#define hb_atomic_ptr_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
+
+ #endif
+
+-/* TODO Add tracing. */
++
++#define HB_ATOMIC_INT_INIT(V) {HB_ATOMIC_INT_IMPL_INIT(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); }
++ inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
++};
++
++
++#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
++#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
++
+
+ #endif /* HB_ATOMIC_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-blob.cc gfx/harfbuzz/src/hb-blob.cc
+--- gfx/harfbuzz/src_old/hb-blob.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-blob.cc 2016-06-05 23:48:18.064359059 +0200
+@@ -78,8 +78,8 @@
+ }
+
+ /**
+- * hb_blob_create: (Xconstructor)
+- * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data.
++ * 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.
+@@ -91,7 +91,7 @@
+ * Return value: New blob, or the empty blob if something failed or if @length is
+ * zero. Destroy with hb_blob_destroy().
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_blob_create (const char *data,
+@@ -147,7 +147,7 @@
+ * @length is zero or @offset is beyond the end of @parent's data. Destroy
+ * with hb_blob_destroy().
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_blob_create_sub_blob (hb_blob_t *parent,
+@@ -179,7 +179,7 @@
+ *
+ * Return value: (transfer full): the empty blob.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_blob_get_empty (void)
+@@ -210,7 +210,7 @@
+ *
+ * Return value: @blob.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_blob_reference (hb_blob_t *blob)
+@@ -228,7 +228,7 @@
+ *
+ * See TODO:link object types for more information.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_blob_destroy (hb_blob_t *blob)
+@@ -250,7 +250,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_blob_set_user_data (hb_blob_t *blob,
+@@ -271,7 +271,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_blob_get_user_data (hb_blob_t *blob,
+@@ -287,7 +287,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_blob_make_immutable (hb_blob_t *blob)
+@@ -306,7 +306,7 @@
+ *
+ * Return value: TODO
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_blob_is_immutable (hb_blob_t *blob)
+@@ -323,7 +323,7 @@
+ *
+ * Return value: the length of blob data in bytes.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ unsigned int
+ hb_blob_get_length (hb_blob_t *blob)
+@@ -340,7 +340,7 @@
+ *
+ * Returns: (transfer none) (array length=length):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ const char *
+ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
+@@ -365,7 +365,7 @@
+ * Returns: (transfer none) (array length=length): Writable blob data,
+ * or %NULL if failed.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ char *
+ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
+diff -uN gfx/harfbuzz/src_old/hb-blob.h gfx/harfbuzz/src/hb-blob.h
+--- gfx/harfbuzz/src_old/hb-blob.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-blob.h 2016-06-05 23:48:19.231352500 +0200
+@@ -64,7 +64,7 @@
+
+ typedef struct hb_blob_t hb_blob_t;
+
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_blob_create (const char *data,
+ unsigned int length,
+ hb_memory_mode_t mode,
+@@ -77,21 +77,21 @@
+ * modify the parent data as that data may be
+ * shared among multiple sub-blobs.
+ */
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_blob_create_sub_blob (hb_blob_t *parent,
+ unsigned int offset,
+ unsigned int length);
+
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_blob_get_empty (void);
+
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_blob_reference (hb_blob_t *blob);
+
+-void
++HB_EXTERN void
+ hb_blob_destroy (hb_blob_t *blob);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_blob_set_user_data (hb_blob_t *blob,
+ hb_user_data_key_t *key,
+ void * data,
+@@ -99,25 +99,25 @@
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_blob_get_user_data (hb_blob_t *blob,
+ hb_user_data_key_t *key);
+
+
+-void
++HB_EXTERN void
+ hb_blob_make_immutable (hb_blob_t *blob);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_blob_is_immutable (hb_blob_t *blob);
+
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_blob_get_length (hb_blob_t *blob);
+
+-const char *
++HB_EXTERN const char *
+ hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
+
+-char *
++HB_EXTERN char *
+ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-buffer.cc gfx/harfbuzz/src/hb-buffer.cc
+--- gfx/harfbuzz/src_old/hb-buffer.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer.cc 2016-06-05 23:48:28.261301901 +0200
+@@ -35,7 +35,28 @@
+ #define HB_DEBUG_BUFFER (HB_DEBUG+0)
+ #endif
+
++/**
++ * SECTION: hb-buffer
++ * @title: Buffers
++ * @short_description: Input and output buffers
++ * @include: hb.h
++ *
++ * Buffers serve dual role in HarfBuzz; they hold the input characters that are
++ * passed hb_shape(), and after shaping they hold the output glyphs.
++ **/
+
++/**
++ * hb_segment_properties_equal:
++ * @a: first #hb_segment_properties_t to compare.
++ * @b: second #hb_segment_properties_t to compare.
++ *
++ * Checks the equality of two #hb_segment_properties_t's.
++ *
++ * Return value: (transfer full):
++ * %true if all properties of @a equal those of @b, false otherwise.
++ *
++ * Since: 0.9.7
++ **/
+ hb_bool_t
+ hb_segment_properties_equal (const hb_segment_properties_t *a,
+ const hb_segment_properties_t *b)
+@@ -48,6 +69,17 @@
+
+ }
+
++/**
++ * hb_segment_properties_hash:
++ * @p: #hb_segment_properties_t to hash.
++ *
++ * Creates a hash representing @p.
++ *
++ * Return value:
++ * A hash of @p.
++ *
++ * Since: 0.9.7
++ **/
+ unsigned int
+ hb_segment_properties_hash (const hb_segment_properties_t *p)
+ {
+@@ -85,6 +117,11 @@
+ {
+ if (unlikely (in_error))
+ return false;
++ if (unlikely (size > max_len))
++ {
++ in_error = true;
++ return false;
++ }
+
+ unsigned int new_allocated = allocated;
+ hb_glyph_position_t *new_pos = NULL;
+@@ -192,6 +229,7 @@
+
+ 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;
+@@ -443,7 +481,7 @@
+ {
+ unsigned int i, j;
+
+- if (start == end - 1)
++ if (end - start < 2)
+ return;
+
+ for (i = start, j = end - 1; i < j; i++, j--) {
+@@ -454,7 +492,7 @@
+ info[j] = t;
+ }
+
+- if (pos) {
++ if (have_positions) {
+ for (i = start, j = end - 1; i < j; i++, j--) {
+ hb_glyph_position_t t;
+
+@@ -498,14 +536,10 @@
+ }
+
+ void
+-hb_buffer_t::merge_clusters (unsigned int start,
+- unsigned int end)
++hb_buffer_t::merge_clusters_impl (unsigned int start,
++ unsigned int end)
+ {
+-#ifdef HB_NO_MERGE_CLUSTERS
+- return;
+-#endif
+-
+- if (unlikely (end - start < 2))
++ if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+ return;
+
+ unsigned int cluster = info[start].cluster;
+@@ -523,7 +557,7 @@
+
+ /* If we hit the start of buffer, continue in out-buffer. */
+ if (idx == start)
+- for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
++ for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+ out_info[i - 1].cluster = cluster;
+
+ for (unsigned int i = start; i < end; i++)
+@@ -533,9 +567,8 @@
+ hb_buffer_t::merge_out_clusters (unsigned int start,
+ unsigned int end)
+ {
+-#ifdef HB_NO_MERGE_CLUSTERS
+- return;
+-#endif
++ if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
++ return;
+
+ if (unlikely (end - start < 2))
+ return;
+@@ -555,12 +588,44 @@
+
+ /* If we hit the end of out-buffer, continue in buffer. */
+ if (end == out_len)
+- for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
++ for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+ info[i].cluster = cluster;
+
+ for (unsigned int i = start; i < end; i++)
+ out_info[i].cluster = cluster;
+ }
++void
++hb_buffer_t::delete_glyph ()
++{
++ unsigned int cluster = info[idx].cluster;
++ if (idx + 1 < len && cluster == info[idx + 1].cluster)
++ {
++ /* Cluster survives; do nothing. */
++ goto done;
++ }
++
++ if (out_len)
++ {
++ /* Merge cluster backward. */
++ if (cluster < out_info[out_len - 1].cluster)
++ {
++ unsigned int old_cluster = out_info[out_len - 1].cluster;
++ for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
++ out_info[i - 1].cluster = cluster;
++ }
++ goto done;
++ }
++
++ if (idx + 1 < len)
++ {
++ /* Merge cluster forward. */
++ merge_clusters (idx, idx + 2);
++ goto done;
++ }
++
++done:
++ skip_glyph ();
++}
+
+ void
+ hb_buffer_t::guess_segment_properties (void)
+@@ -667,11 +732,16 @@
+ /**
+ * hb_buffer_create: (Xconstructor)
+ *
+- *
++ * Creates a new #hb_buffer_t with all properties to defaults.
+ *
+- * Return value: (transfer full)
++ * Return value: (transfer full):
++ * A newly allocated #hb_buffer_t with a reference count of 1. The initial
++ * reference count should be released with hb_buffer_destroy() when you are done
++ * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
++ * be allocated, a special #hb_buffer_t object will be returned on which
++ * hb_buffer_allocation_successful() returns %false.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_buffer_t *
+ hb_buffer_create (void)
+@@ -681,6 +751,8 @@
+ if (!(buffer = hb_object_create<hb_buffer_t> ()))
+ return hb_buffer_get_empty ();
+
++ buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
++
+ buffer->reset ();
+
+ return buffer;
+@@ -693,7 +765,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_buffer_t *
+ hb_buffer_get_empty (void)
+@@ -703,7 +775,10 @@
+
+ const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
+ HB_BUFFER_FLAG_DEFAULT,
++ HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
+ HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
++ HB_BUFFER_SCRATCH_FLAG_DEFAULT,
++ HB_BUFFER_MAX_LEN_DEFAULT,
+
+ HB_BUFFER_CONTENT_TYPE_INVALID,
+ HB_SEGMENT_PROPERTIES_DEFAULT,
+@@ -719,13 +794,15 @@
+
+ /**
+ * hb_buffer_reference: (skip)
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Increases the reference count on @buffer by one. This prevents @buffer from
++ * being destroyed until a matching call to hb_buffer_destroy() is made.
+ *
+ * Return value: (transfer full):
++ * The referenced #hb_buffer_t.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_buffer_t *
+ hb_buffer_reference (hb_buffer_t *buffer)
+@@ -735,11 +812,13 @@
+
+ /**
+ * hb_buffer_destroy: (skip)
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Deallocate the @buffer.
++ * Decreases the reference count on @buffer by one. If the result is zero, then
++ * @buffer and all associated resources are freed. See hb_buffer_reference().
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_destroy (hb_buffer_t *buffer)
+@@ -750,13 +829,15 @@
+
+ free (buffer->info);
+ free (buffer->pos);
++ if (buffer->message_destroy)
++ buffer->message_destroy (buffer->message_data);
+
+ free (buffer);
+ }
+
+ /**
+ * hb_buffer_set_user_data: (skip)
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @key:
+ * @data:
+ * @destroy:
+@@ -766,7 +847,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_set_user_data (hb_buffer_t *buffer,
+@@ -780,14 +861,14 @@
+
+ /**
+ * hb_buffer_get_user_data: (skip)
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @key:
+ *
+ *
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_buffer_get_user_data (hb_buffer_t *buffer,
+@@ -799,12 +880,13 @@
+
+ /**
+ * hb_buffer_set_content_type:
+- * @buffer: a buffer.
+- * @content_type:
++ * @buffer: an #hb_buffer_t.
++ * @content_type: the type of buffer contents to set
+ *
+- *
++ * Sets the type of @buffer contents, buffers are either empty, contain
++ * characters (before shaping) or glyphs (the result of shaping).
+ *
+- * Since: 1.0
++ * Since: 0.9.5
+ **/
+ void
+ hb_buffer_set_content_type (hb_buffer_t *buffer,
+@@ -815,13 +897,14 @@
+
+ /**
+ * hb_buffer_get_content_type:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * see hb_buffer_set_content_type().
+ *
+- * Return value:
++ * Return value:
++ * The type of @buffer contents.
+ *
+- * Since: 1.0
++ * Since: 0.9.5
+ **/
+ hb_buffer_content_type_t
+ hb_buffer_get_content_type (hb_buffer_t *buffer)
+@@ -832,12 +915,12 @@
+
+ /**
+ * hb_buffer_set_unicode_funcs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @unicode_funcs:
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
+@@ -857,13 +940,13 @@
+
+ /**
+ * hb_buffer_get_unicode_funcs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ *
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
+@@ -873,12 +956,18 @@
+
+ /**
+ * hb_buffer_set_direction:
+- * @buffer: a buffer.
+- * @direction:
++ * @buffer: an #hb_buffer_t.
++ * @direction: the #hb_direction_t of the @buffer
+ *
+- *
++ * Set the text flow direction of the buffer. No shaping can happen without
++ * setting @buffer direction, and it controls the visual direction for the
++ * output glyphs; for RTL direction the glyphs will be reversed. Many layout
++ * features depend on the proper setting of the direction, for example,
++ * reversing RTL text before shaping, then shaping with LTR direction is not
++ * the same as keeping the text in logical order and shaping with RTL
++ * direction.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_set_direction (hb_buffer_t *buffer,
+@@ -893,13 +982,14 @@
+
+ /**
+ * hb_buffer_get_direction:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_direction()
+ *
+- * Return value:
++ * Return value:
++ * The direction of the @buffer.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_direction_t
+ hb_buffer_get_direction (hb_buffer_t *buffer)
+@@ -909,12 +999,20 @@
+
+ /**
+ * hb_buffer_set_script:
+- * @buffer: a buffer.
+- * @script:
++ * @buffer: an #hb_buffer_t.
++ * @script: an #hb_script_t to set.
+ *
+- *
++ * Sets the script of @buffer to @script.
+ *
+- * Since: 1.0
++ * Script is crucial for choosing the proper shaping behaviour for scripts that
++ * require it (e.g. Arabic) and the which OpenType features defined in the font
++ * to be applied.
++ *
++ * You can pass one of the predefined #hb_script_t values, or use
++ * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
++ * corresponding script from an ISO 15924 script tag.
++ *
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_set_script (hb_buffer_t *buffer,
+@@ -928,13 +1026,14 @@
+
+ /**
+ * hb_buffer_get_script:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_script().
+ *
+- * Return value:
++ * Return value:
++ * The #hb_script_t of the @buffer.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_script_t
+ hb_buffer_get_script (hb_buffer_t *buffer)
+@@ -944,12 +1043,20 @@
+
+ /**
+ * hb_buffer_set_language:
+- * @buffer: a buffer.
+- * @language:
++ * @buffer: an #hb_buffer_t.
++ * @language: an hb_language_t to set.
+ *
+- *
++ * Sets the language of @buffer to @language.
++ *
++ * Languages are crucial for selecting which OpenType feature to apply to the
++ * buffer which can result in applying language-specific behaviour. Languages
++ * are orthogonal to the scripts, and though they are related, they are
++ * different concepts and should not be confused with each other.
++ *
++ * Use hb_language_from_string() to convert from ISO 639 language codes to
++ * #hb_language_t.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_set_language (hb_buffer_t *buffer,
+@@ -963,13 +1070,14 @@
+
+ /**
+ * hb_buffer_get_language:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_language().
+ *
+- * Return value:
++ * Return value: (transfer none):
++ * The #hb_language_t of the buffer. Must not be freed by the caller.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_language_t
+ hb_buffer_get_language (hb_buffer_t *buffer)
+@@ -979,12 +1087,14 @@
+
+ /**
+ * hb_buffer_set_segment_properties:
+- * @buffer: a buffer.
+- * @props:
++ * @buffer: an #hb_buffer_t.
++ * @props: an #hb_segment_properties_t to use.
+ *
+- *
++ * Sets the segment properties of the buffer, a shortcut for calling
++ * hb_buffer_set_direction(), hb_buffer_set_script() and
++ * hb_buffer_set_language() individually.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+@@ -998,12 +1108,12 @@
+
+ /**
+ * hb_buffer_get_segment_properties:
+- * @buffer: a buffer.
+- * @props:
++ * @buffer: an #hb_buffer_t.
++ * @props: (out): the output #hb_segment_properties_t.
+ *
+- *
++ * Sets @props to the #hb_segment_properties_t of @buffer.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+@@ -1015,12 +1125,12 @@
+
+ /**
+ * hb_buffer_set_flags:
+- * @buffer: a buffer.
+- * @flags:
++ * @buffer: an #hb_buffer_t.
++ * @flags: the buffer flags to set.
+ *
+- *
++ * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_set_flags (hb_buffer_t *buffer,
+@@ -1034,13 +1144,14 @@
+
+ /**
+ * hb_buffer_get_flags:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_flags().
+ *
+ * Return value:
++ * The @buffer flags.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_buffer_flags_t
+ hb_buffer_get_flags (hb_buffer_t *buffer)
+@@ -1048,15 +1159,53 @@
+ return buffer->flags;
+ }
+
++/**
++ * hb_buffer_set_cluster_level:
++ * @buffer: an #hb_buffer_t.
++ * @cluster_level:
++ *
++ *
++ *
++ * Since: 0.9.42
++ **/
++void
++hb_buffer_set_cluster_level (hb_buffer_t *buffer,
++ hb_buffer_cluster_level_t cluster_level)
++{
++ if (unlikely (hb_object_is_inert (buffer)))
++ return;
++
++ buffer->cluster_level = cluster_level;
++}
++
++/**
++ * hb_buffer_get_cluster_level:
++ * @buffer: an #hb_buffer_t.
++ *
++ *
++ *
++ * Return value:
++ *
++ * Since: 0.9.42
++ **/
++hb_buffer_cluster_level_t
++hb_buffer_get_cluster_level (hb_buffer_t *buffer)
++{
++ return buffer->cluster_level;
++}
++
+
+ /**
+ * hb_buffer_set_replacement_codepoint:
+- * @buffer: a buffer.
+- * @replacement:
++ * @buffer: an #hb_buffer_t.
++ * @replacement: the replacement #hb_codepoint_t
+ *
+- *
++ * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
++ * when adding text to @buffer.
+ *
+- * Since: 1.0
++ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
++ *
++ * Since: 0.9.31
+ **/
+ void
+ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
+@@ -1070,13 +1219,14 @@
+
+ /**
+ * hb_buffer_get_replacement_codepoint:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_replacement_codepoint().
+ *
+ * Return value:
++ * The @buffer replacement #hb_codepoint_t.
+ *
+- * Since: 1.0
++ * Since: 0.9.31
+ **/
+ hb_codepoint_t
+ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
+@@ -1087,11 +1237,12 @@
+
+ /**
+ * hb_buffer_reset:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Resets the buffer to its initial status, as if it was just newly created
++ * with hb_buffer_create().
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_reset (hb_buffer_t *buffer)
+@@ -1101,11 +1252,12 @@
+
+ /**
+ * hb_buffer_clear_contents:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
++ * the replacement code point.
+ *
+- * Since: 1.0
++ * Since: 0.9.11
+ **/
+ void
+ hb_buffer_clear_contents (hb_buffer_t *buffer)
+@@ -1115,14 +1267,15 @@
+
+ /**
+ * hb_buffer_pre_allocate:
+- * @buffer: a buffer.
+- * @size:
++ * @buffer: an #hb_buffer_t.
++ * @size: number of items to pre allocate.
+ *
+- *
++ * Pre allocates memory for @buffer to fit at least @size number of items.
+ *
+- * Return value:
++ * Return value:
++ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
+@@ -1132,13 +1285,14 @@
+
+ /**
+ * hb_buffer_allocation_successful:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Check if allocating memory for the buffer succeeded.
+ *
+- * Return value:
++ * Return value:
++ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_allocation_successful (hb_buffer_t *buffer)
+@@ -1148,13 +1302,20 @@
+
+ /**
+ * hb_buffer_add:
+- * @buffer: a buffer.
+- * @codepoint:
+- * @cluster:
++ * @buffer: an #hb_buffer_t.
++ * @codepoint: a Unicode code point.
++ * @cluster: the cluster value of @codepoint.
++ *
++ * Appends a character with the Unicode value of @codepoint to @buffer, and
++ * gives it the initial cluster value of @cluster. Clusters can be any thing
++ * the client wants, they are usually used to refer to the index of the
++ * character in the input text stream and are output in
++ * #hb_glyph_info_t.cluster field.
+ *
+- *
++ * This function does not check the validity of @codepoint, it is up to the
++ * caller to ensure it is a valid Unicode code point.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_add (hb_buffer_t *buffer,
+@@ -1167,14 +1328,16 @@
+
+ /**
+ * hb_buffer_set_length:
+- * @buffer: a buffer.
+- * @length:
++ * @buffer: an #hb_buffer_t.
++ * @length: the new length of @buffer.
+ *
+- *
++ * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
++ * end.
+ *
+ * Return value:
++ * %true if @buffer memory allocation succeeded, %false otherwise.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_set_length (hb_buffer_t *buffer,
+@@ -1207,13 +1370,15 @@
+
+ /**
+ * hb_buffer_get_length:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ * Returns the number of items in the buffer.
+ *
+- * Return value: buffer length.
++ * Return value:
++ * The @buffer length.
++ * The value valid as long as buffer has not been modified.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ unsigned int
+ hb_buffer_get_length (hb_buffer_t *buffer)
+@@ -1223,15 +1388,17 @@
+
+ /**
+ * hb_buffer_get_glyph_infos:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @length: (out): output array length.
+ *
+- * Returns buffer glyph information array. Returned pointer
+- * is valid as long as buffer contents are not modified.
++ * Returns @buffer glyph information array. Returned pointer
++ * is valid as long as @buffer contents are not modified.
+ *
+- * Return value: (transfer none) (array length=length): buffer glyph information array.
++ * Return value: (transfer none) (array length=length):
++ * The @buffer glyph information array.
++ * The value valid as long as buffer has not been modified.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_glyph_info_t *
+ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
+@@ -1245,15 +1412,17 @@
+
+ /**
+ * hb_buffer_get_glyph_positions:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @length: (out): output length.
+ *
+- * Returns buffer glyph position array. Returned pointer
+- * is valid as long as buffer contents are not modified.
++ * Returns @buffer glyph position array. Returned pointer
++ * is valid as long as @buffer contents are not modified.
+ *
+- * Return value: (transfer none) (array length=length): buffer glyph position array.
++ * Return value: (transfer none) (array length=length):
++ * The @buffer glyph position array.
++ * The value valid as long as buffer has not been modified.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_glyph_position_t *
+ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
+@@ -1270,11 +1439,11 @@
+
+ /**
+ * hb_buffer_reverse:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ * Reverses buffer contents.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_reverse (hb_buffer_t *buffer)
+@@ -1283,14 +1452,31 @@
+ }
+
+ /**
++ * hb_buffer_reverse_range:
++ * @buffer: an #hb_buffer_t.
++ * @start: start index.
++ * @end: end index.
++ *
++ * Reverses buffer contents between start to end.
++ *
++ * Since: 0.9.41
++ **/
++void
++hb_buffer_reverse_range (hb_buffer_t *buffer,
++ unsigned int start, unsigned int end)
++{
++ buffer->reverse_range (start, end);
++}
++
++/**
+ * hb_buffer_reverse_clusters:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ * Reverses buffer clusters. That is, the buffer contents are
+ * reversed, then each cluster (consecutive items having the
+ * same cluster number) are reversed again.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
+@@ -1300,7 +1486,7 @@
+
+ /**
+ * hb_buffer_guess_segment_properties:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ * Sets unset buffer segment properties based on buffer Unicode
+ * contents. If buffer is not empty, it must have content type
+@@ -1320,7 +1506,7 @@
+ * hb_language_get_default(). This may change in the future by
+ * taking buffer script into consideration when choosing a language.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
+@@ -1328,15 +1514,15 @@
+ buffer->guess_segment_properties ();
+ }
+
+-template <bool validate, typename T>
++template <typename utf_t>
+ static inline void
+ hb_buffer_add_utf (hb_buffer_t *buffer,
+- const T *text,
++ const typename utf_t::codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length)
+ {
+- typedef hb_utf_t<T, true> utf_t;
++ typedef typename utf_t::codepoint_t T;
+ const hb_codepoint_t replacement = buffer->replacement;
+
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+@@ -1399,15 +1585,20 @@
+
+ /**
+ * hb_buffer_add_utf8:
+- * @buffer: a buffer.
+- * @text: (array length=text_length):
+- * @text_length:
+- * @item_offset:
+- * @item_length:
++ * @buffer: an #hb_buffer_t.
++ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
++ * characters to append.
++ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
++ * @item_offset: the offset of the first character to add to the @buffer.
++ * @item_length: the number of characters to add to the @buffer, or -1 for the
++ * end of @text (assuming it is %NULL terminated).
+ *
+- *
++ * See hb_buffer_add_codepoints().
+ *
+- * Since: 1.0
++ * Replaces invalid UTF-8 characters with the @buffer replacement code point,
++ * see hb_buffer_set_replacement_codepoint().
++ *
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_add_utf8 (hb_buffer_t *buffer,
+@@ -1416,20 +1607,24 @@
+ unsigned int item_offset,
+ int item_length)
+ {
+- hb_buffer_add_utf<true> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
++ hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
+ }
+
+ /**
+ * hb_buffer_add_utf16:
+- * @buffer: a buffer.
+- * @text: (array length=text_length):
+- * @text_length:
+- * @item_offset:
+- * @item_length:
++ * @buffer: an #hb_buffer_t.
++ * @text: (array length=text_length): an array of UTF-16 characters to append.
++ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
++ * @item_offset: the offset of the first character to add to the @buffer.
++ * @item_length: the number of characters to add to the @buffer, or -1 for the
++ * end of @text (assuming it is %NULL terminated).
+ *
+- *
++ * See hb_buffer_add_codepoints().
+ *
+- * Since: 1.0
++ * Replaces invalid UTF-16 characters with the @buffer replacement code point,
++ * see hb_buffer_set_replacement_codepoint().
++ *
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_add_utf16 (hb_buffer_t *buffer,
+@@ -1438,20 +1633,24 @@
+ unsigned int item_offset,
+ int item_length)
+ {
+- hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
++ hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
+ }
+
+ /**
+ * hb_buffer_add_utf32:
+- * @buffer: a buffer.
+- * @text: (array length=text_length):
+- * @text_length:
+- * @item_offset:
+- * @item_length:
++ * @buffer: an #hb_buffer_t.
++ * @text: (array length=text_length): an array of UTF-32 characters to append.
++ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
++ * @item_offset: the offset of the first character to add to the @buffer.
++ * @item_length: the number of characters to add to the @buffer, or -1 for the
++ * end of @text (assuming it is %NULL terminated).
+ *
+- *
++ * See hb_buffer_add_codepoints().
+ *
+- * Since: 1.0
++ * Replaces invalid UTF-32 characters with the @buffer replacement code point,
++ * see hb_buffer_set_replacement_codepoint().
++ *
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_add_utf32 (hb_buffer_t *buffer,
+@@ -1460,20 +1659,59 @@
+ unsigned int item_offset,
+ int item_length)
+ {
+- hb_buffer_add_utf<true> (buffer, text, text_length, item_offset, item_length);
++ hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
++}
++
++/**
++ * hb_buffer_add_latin1:
++ * @buffer: an #hb_buffer_t.
++ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
++ * characters to append.
++ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
++ * @item_offset: the offset of the first character to add to the @buffer.
++ * @item_length: the number of characters to add to the @buffer, or -1 for the
++ * end of @text (assuming it is %NULL terminated).
++ *
++ * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
++ * Unicode code points that can fit in 8-bit strings.
++ *
++ * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
++ *
++ * Since: 0.9.39
++ **/
++void
++hb_buffer_add_latin1 (hb_buffer_t *buffer,
++ const uint8_t *text,
++ int text_length,
++ unsigned int item_offset,
++ int item_length)
++{
++ hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
+ }
+
+ /**
+ * hb_buffer_add_codepoints:
+- * @buffer: a buffer.
+- * @text: (array length=text_length):
+- * @text_length:
+- * @item_offset:
+- * @item_length:
++ * @buffer: a #hb_buffer_t to append characters to.
++ * @text: (array length=text_length): an array of Unicode code points to append.
++ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
++ * @item_offset: the offset of the first code point to add to the @buffer.
++ * @item_length: the number of code points to add to the @buffer, or -1 for the
++ * end of @text (assuming it is %NULL terminated).
++ *
++ * Appends characters from @text array to @buffer. The @item_offset is the
++ * position of the first character from @text that will be appended, and
++ * @item_length is the number of character. When shaping part of a larger text
++ * (e.g. a run of text from a paragraph), instead of passing just the substring
++ * corresponding to the run, it is preferable to pass the whole
++ * paragraph and specify the run start and length as @item_offset and
++ * @item_length, respectively, to give HarfBuzz the full context to be able,
++ * for example, to do cross-run Arabic shaping or properly handle combining
++ * marks at stat of run.
+ *
+- *
++ * This function does not check the validity of @text, it is up to the caller
++ * to ensure it contains a valid Unicode code points.
+ *
+- * Since: 1.0
++ * Since: 0.9.31
+ **/
+ void
+ hb_buffer_add_codepoints (hb_buffer_t *buffer,
+@@ -1482,7 +1720,7 @@
+ unsigned int item_offset,
+ int item_length)
+ {
+- hb_buffer_add_utf<false> (buffer, text, text_length, item_offset, item_length);
++ hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
+ }
+
+
+@@ -1528,7 +1766,7 @@
+ pos[end - 1].x_advance = total_x_advance;
+ pos[end - 1].y_advance = total_y_advance;
+
+- hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
++ hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+ } else {
+ /* Transfer all cluster advance to the first glyph. */
+ pos[start].x_advance += total_x_advance;
+@@ -1537,17 +1775,20 @@
+ pos[i].x_offset -= total_x_advance;
+ pos[i].y_offset -= total_y_advance;
+ }
+- hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
++ hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+ }
+ }
+
+ /**
+ * hb_buffer_normalize_glyphs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
++ * The resulting clusters should behave identical to pre-reordering clusters.
+ *
+- * Since: 1.0
++ * <note>This has nothing to do with Unicode normalization.</note>
++ *
++ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+@@ -1570,3 +1811,66 @@
+ }
+ normalize_glyphs_cluster (buffer, start, end, backward);
+ }
++
++void
++hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *))
++{
++ assert (!have_positions);
++ for (unsigned int i = start + 1; i < end; i++)
++ {
++ unsigned int j = i;
++ while (j > start && compar (&info[j - 1], &info[i]) > 0)
++ j--;
++ if (i == j)
++ continue;
++ /* Move item i to occupy place for item j, shift what's in between. */
++ merge_clusters (j, i + 1);
++ {
++ hb_glyph_info_t t = info[i];
++ memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t));
++ info[j] = t;
++ }
++ }
++}
++
++/*
++ * Debugging.
++ */
++
++/**
++ * hb_buffer_set_message_func:
++ * @buffer: an #hb_buffer_t.
++ * @func: (closure user_data) (destroy destroy) (scope notified):
++ * @user_data:
++ * @destroy:
++ *
++ *
++ *
++ * Since: 1.1.3
++ **/
++void
++hb_buffer_set_message_func (hb_buffer_t *buffer,
++ hb_buffer_message_func_t func,
++ void *user_data, hb_destroy_func_t destroy)
++{
++ if (buffer->message_destroy)
++ buffer->message_destroy (buffer->message_data);
++
++ if (func) {
++ buffer->message_func = func;
++ buffer->message_data = user_data;
++ buffer->message_destroy = destroy;
++ } else {
++ buffer->message_func = NULL;
++ buffer->message_data = NULL;
++ buffer->message_destroy = NULL;
++ }
++}
++
++bool
++hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
++{
++ char buf[100];
++ vsnprintf (buf, sizeof (buf), fmt, ap);
++ return (bool) this->message_func (this, font, buf, this->message_data);
++}
+diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-json.hh gfx/harfbuzz/src/hb-buffer-deserialize-json.hh
+--- gfx/harfbuzz/src_old/hb-buffer-deserialize-json.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer-deserialize-json.hh 2016-06-05 23:48:20.553345078 +0200
+@@ -1,5 +1,5 @@
+
+-#line 1 "../../src/hb-buffer-deserialize-json.rl"
++#line 1 "hb-buffer-deserialize-json.rl"
+ /*
+ * Copyright © 2013 Google, Inc.
+ *
+@@ -32,7 +32,7 @@
+ #include "hb-private.hh"
+
+
+-#line 36 "hb-buffer-deserialize-json.hh.tmp"
++#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,
+@@ -435,7 +435,7 @@
+ static const int deserialize_json_en_main = 1;
+
+
+-#line 97 "../../src/hb-buffer-deserialize-json.rl"
++#line 97 "hb-buffer-deserialize-json.rl"
+
+
+ static hb_bool_t
+@@ -459,15 +459,15 @@
+
+ const char *tok = NULL;
+ int cs;
+- hb_glyph_info_t info;
+- hb_glyph_position_t pos;
++ hb_glyph_info_t info = {0};
++ hb_glyph_position_t pos = {0};
+
+-#line 466 "hb-buffer-deserialize-json.hh.tmp"
++#line 466 "hb-buffer-deserialize-json.hh"
+ {
+ cs = deserialize_json_start;
+ }
+
+-#line 471 "hb-buffer-deserialize-json.hh.tmp"
++#line 471 "hb-buffer-deserialize-json.hh"
+ {
+ int _slen;
+ int _trans;
+@@ -493,14 +493,14 @@
+
+ switch ( _deserialize_json_trans_actions[_trans] ) {
+ case 1:
+-#line 38 "../../src/hb-buffer-deserialize-json.rl"
++#line 38 "hb-buffer-deserialize-json.rl"
+ {
+ memset (&info, 0, sizeof (info));
+ memset (&pos , 0, sizeof (pos ));
+ }
+ break;
+ case 5:
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -510,13 +510,13 @@
+ }
+ break;
+ case 2:
+-#line 51 "../../src/hb-buffer-deserialize-json.rl"
++#line 51 "hb-buffer-deserialize-json.rl"
+ {
+ tok = p;
+ }
+ break;
+ case 14:
+-#line 55 "../../src/hb-buffer-deserialize-json.rl"
++#line 55 "hb-buffer-deserialize-json.rl"
+ {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+@@ -525,33 +525,33 @@
+ }
+ break;
+ case 15:
+-#line 62 "../../src/hb-buffer-deserialize-json.rl"
++#line 62 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+ break;
+ case 8:
+-#line 63 "../../src/hb-buffer-deserialize-json.rl"
++#line 63 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.cluster )) return false; }
+ break;
+ case 10:
+-#line 64 "../../src/hb-buffer-deserialize-json.rl"
++#line 64 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+ break;
+ case 12:
+-#line 65 "../../src/hb-buffer-deserialize-json.rl"
++#line 65 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+ break;
+ case 3:
+-#line 66 "../../src/hb-buffer-deserialize-json.rl"
++#line 66 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+ break;
+ case 6:
+-#line 67 "../../src/hb-buffer-deserialize-json.rl"
++#line 67 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+ break;
+ case 16:
+-#line 62 "../../src/hb-buffer-deserialize-json.rl"
++#line 62 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -561,9 +561,9 @@
+ }
+ break;
+ case 9:
+-#line 63 "../../src/hb-buffer-deserialize-json.rl"
++#line 63 "hb-buffer-deserialize-json.rl"
+ { if (!parse_uint (tok, p, &info.cluster )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -573,9 +573,9 @@
+ }
+ break;
+ case 11:
+-#line 64 "../../src/hb-buffer-deserialize-json.rl"
++#line 64 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -585,9 +585,9 @@
+ }
+ break;
+ case 13:
+-#line 65 "../../src/hb-buffer-deserialize-json.rl"
++#line 65 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -597,9 +597,9 @@
+ }
+ break;
+ case 4:
+-#line 66 "../../src/hb-buffer-deserialize-json.rl"
++#line 66 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -609,9 +609,9 @@
+ }
+ break;
+ case 7:
+-#line 67 "../../src/hb-buffer-deserialize-json.rl"
++#line 67 "hb-buffer-deserialize-json.rl"
+ { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-json.rl"
++#line 43 "hb-buffer-deserialize-json.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -620,7 +620,7 @@
+ *end_ptr = p;
+ }
+ break;
+-#line 624 "hb-buffer-deserialize-json.hh.tmp"
++#line 624 "hb-buffer-deserialize-json.hh"
+ }
+
+ _again:
+@@ -632,7 +632,7 @@
+ _out: {}
+ }
+
+-#line 125 "../../src/hb-buffer-deserialize-json.rl"
++#line 125 "hb-buffer-deserialize-json.rl"
+
+
+ *end_ptr = p;
+diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-text.hh gfx/harfbuzz/src/hb-buffer-deserialize-text.hh
+--- gfx/harfbuzz/src_old/hb-buffer-deserialize-text.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer-deserialize-text.hh 2016-06-05 23:48:23.120330665 +0200
+@@ -1,5 +1,5 @@
+
+-#line 1 "../../src/hb-buffer-deserialize-text.rl"
++#line 1 "hb-buffer-deserialize-text.rl"
+ /*
+ * Copyright © 2013 Google, Inc.
+ *
+@@ -32,7 +32,7 @@
+ #include "hb-private.hh"
+
+
+-#line 36 "hb-buffer-deserialize-text.hh.tmp"
++#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,
+@@ -312,7 +312,7 @@
+ static const int deserialize_text_en_main = 1;
+
+
+-#line 91 "../../src/hb-buffer-deserialize-text.rl"
++#line 91 "hb-buffer-deserialize-text.rl"
+
+
+ static hb_bool_t
+@@ -336,15 +336,15 @@
+
+ const char *eof = pe, *tok = NULL;
+ int cs;
+- hb_glyph_info_t info;
+- hb_glyph_position_t pos;
++ hb_glyph_info_t info = {0};
++ hb_glyph_position_t pos = {0};
+
+-#line 343 "hb-buffer-deserialize-text.hh.tmp"
++#line 343 "hb-buffer-deserialize-text.hh"
+ {
+ cs = deserialize_text_start;
+ }
+
+-#line 348 "hb-buffer-deserialize-text.hh.tmp"
++#line 348 "hb-buffer-deserialize-text.hh"
+ {
+ int _slen;
+ int _trans;
+@@ -370,13 +370,13 @@
+
+ switch ( _deserialize_text_trans_actions[_trans] ) {
+ case 2:
+-#line 51 "../../src/hb-buffer-deserialize-text.rl"
++#line 51 "hb-buffer-deserialize-text.rl"
+ {
+ tok = p;
+ }
+ break;
+ case 5:
+-#line 55 "../../src/hb-buffer-deserialize-text.rl"
++#line 55 "hb-buffer-deserialize-text.rl"
+ {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+@@ -385,41 +385,41 @@
+ }
+ break;
+ case 10:
+-#line 62 "../../src/hb-buffer-deserialize-text.rl"
++#line 62 "hb-buffer-deserialize-text.rl"
+ { if (!parse_uint (tok, p, &info.cluster )) return false; }
+ break;
+ case 3:
+-#line 63 "../../src/hb-buffer-deserialize-text.rl"
++#line 63 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+ break;
+ case 12:
+-#line 64 "../../src/hb-buffer-deserialize-text.rl"
++#line 64 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+ break;
+ case 7:
+-#line 65 "../../src/hb-buffer-deserialize-text.rl"
++#line 65 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+ break;
+ case 1:
+-#line 38 "../../src/hb-buffer-deserialize-text.rl"
++#line 38 "hb-buffer-deserialize-text.rl"
+ {
+ memset (&info, 0, sizeof (info));
+ memset (&pos , 0, sizeof (pos ));
+ }
+-#line 51 "../../src/hb-buffer-deserialize-text.rl"
++#line 51 "hb-buffer-deserialize-text.rl"
+ {
+ tok = p;
+ }
+ break;
+ case 4:
+-#line 55 "../../src/hb-buffer-deserialize-text.rl"
++#line 55 "hb-buffer-deserialize-text.rl"
+ {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+ &info.codepoint))
+ return false;
+ }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -429,9 +429,9 @@
+ }
+ break;
+ case 9:
+-#line 62 "../../src/hb-buffer-deserialize-text.rl"
++#line 62 "hb-buffer-deserialize-text.rl"
+ { if (!parse_uint (tok, p, &info.cluster )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -441,9 +441,9 @@
+ }
+ break;
+ case 11:
+-#line 64 "../../src/hb-buffer-deserialize-text.rl"
++#line 64 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -453,9 +453,9 @@
+ }
+ break;
+ case 6:
+-#line 65 "../../src/hb-buffer-deserialize-text.rl"
++#line 65 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -465,9 +465,9 @@
+ }
+ break;
+ case 8:
+-#line 66 "../../src/hb-buffer-deserialize-text.rl"
++#line 66 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -476,7 +476,7 @@
+ *end_ptr = p;
+ }
+ break;
+-#line 480 "hb-buffer-deserialize-text.hh.tmp"
++#line 480 "hb-buffer-deserialize-text.hh"
+ }
+
+ _again:
+@@ -489,14 +489,14 @@
+ {
+ switch ( _deserialize_text_eof_actions[cs] ) {
+ case 4:
+-#line 55 "../../src/hb-buffer-deserialize-text.rl"
++#line 55 "hb-buffer-deserialize-text.rl"
+ {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+ &info.codepoint))
+ return false;
+ }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -506,9 +506,9 @@
+ }
+ break;
+ case 9:
+-#line 62 "../../src/hb-buffer-deserialize-text.rl"
++#line 62 "hb-buffer-deserialize-text.rl"
+ { if (!parse_uint (tok, p, &info.cluster )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -518,9 +518,9 @@
+ }
+ break;
+ case 11:
+-#line 64 "../../src/hb-buffer-deserialize-text.rl"
++#line 64 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -530,9 +530,9 @@
+ }
+ break;
+ case 6:
+-#line 65 "../../src/hb-buffer-deserialize-text.rl"
++#line 65 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -542,9 +542,9 @@
+ }
+ break;
+ case 8:
+-#line 66 "../../src/hb-buffer-deserialize-text.rl"
++#line 66 "hb-buffer-deserialize-text.rl"
+ { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+-#line 43 "../../src/hb-buffer-deserialize-text.rl"
++#line 43 "hb-buffer-deserialize-text.rl"
+ {
+ buffer->add_info (info);
+ if (buffer->in_error)
+@@ -553,14 +553,14 @@
+ *end_ptr = p;
+ }
+ break;
+-#line 557 "hb-buffer-deserialize-text.hh.tmp"
++#line 557 "hb-buffer-deserialize-text.hh"
+ }
+ }
+
+ _out: {}
+ }
+
+-#line 119 "../../src/hb-buffer-deserialize-text.rl"
++#line 119 "hb-buffer-deserialize-text.rl"
+
+
+ *end_ptr = p;
+diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-text.rl gfx/harfbuzz/src/hb-buffer-deserialize-text.rl
+--- gfx/harfbuzz/src_old/hb-buffer-deserialize-text.rl 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer-deserialize-text.rl 2016-06-05 23:48:24.307324017 +0200
+@@ -111,8 +111,8 @@
+
+ const char *eof = pe, *tok = NULL;
+ int cs;
+- hb_glyph_info_t info;
+- hb_glyph_position_t pos;
++ hb_glyph_info_t info = {0};
++ hb_glyph_position_t pos = {0};
+ %%{
+ write init;
+ write exec;
+diff -uN gfx/harfbuzz/src_old/hb-buffer.h gfx/harfbuzz/src/hb-buffer.h
+--- gfx/harfbuzz/src_old/hb-buffer.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer.h 2016-06-05 23:48:29.670294025 +0200
+@@ -40,7 +40,27 @@
+
+ HB_BEGIN_DECLS
+
+-
++/**
++ * hb_glyph_info_t:
++ * @codepoint: either a Unicode code point (before shaping) or a glyph index
++ * (after shaping).
++ * @mask:
++ * @cluster: the index of the character in the original text that corresponds
++ * to this #hb_glyph_info_t, or whatever the client passes to
++ * hb_buffer_add(). More than one #hb_glyph_info_t can have the same
++ * @cluster value, if they resulted from the same character (e.g. one
++ * to many glyph substitution), and when more than one character gets
++ * merged in the same glyph (e.g. many to one glyph substitution) the
++ * #hb_glyph_info_t will have the smallest cluster value of them.
++ * By default some characters are merged into the same cluster
++ * (e.g. combining marks have the same cluster as their bases)
++ * even if they are separate glyphs, hb_buffer_set_cluster_level()
++ * allow selecting more fine-grained cluster handling.
++ *
++ * The #hb_glyph_info_t is the structure that holds information about the
++ * glyphs and their relation to input text.
++ *
++ */
+ typedef struct hb_glyph_info_t {
+ hb_codepoint_t codepoint;
+ hb_mask_t mask;
+@@ -51,6 +71,22 @@
+ hb_var_int_t var2;
+ } hb_glyph_info_t;
+
++/**
++ * hb_glyph_position_t:
++ * @x_advance: how much the line advances after drawing this glyph when setting
++ * text in horizontal direction.
++ * @y_advance: how much the line advances after drawing this glyph when setting
++ * text in vertical direction.
++ * @x_offset: how much the glyph moves on the X-axis before drawing it, this
++ * should not affect how much the line advances.
++ * @y_offset: how much the glyph moves on the Y-axis before drawing it, this
++ * should not affect how much the line advances.
++ *
++ * The #hb_glyph_position_t is the structure that holds the positions of the
++ * glyph in both horizontal and vertical directions. All positions in
++ * #hb_glyph_position_t are relative to the current point.
++ *
++ */
+ typedef struct hb_glyph_position_t {
+ hb_position_t x_advance;
+ hb_position_t y_advance;
+@@ -61,7 +97,16 @@
+ hb_var_int_t var;
+ } hb_glyph_position_t;
+
+-
++/**
++ * hb_segment_properties_t:
++ * @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
++ * @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
++ * @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
++ *
++ * The structure that holds various text properties of an #hb_buffer_t. Can be
++ * set and retrieved using hb_buffer_set_segment_properties() and
++ * hb_buffer_get_segment_properties(), respectively.
++ */
+ typedef struct hb_segment_properties_t {
+ hb_direction_t direction;
+ hb_script_t script;
+@@ -77,100 +122,127 @@
+ NULL, \
+ NULL}
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_segment_properties_equal (const hb_segment_properties_t *a,
+ const hb_segment_properties_t *b);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+-/*
+- * hb_buffer_t
++/**
++ * hb_buffer_t:
++ *
++ * The main structure holding the input text and its properties before shaping,
++ * and output glyphs and their information after shaping.
+ */
+
+ typedef struct hb_buffer_t hb_buffer_t;
+
+-hb_buffer_t *
++HB_EXTERN hb_buffer_t *
+ hb_buffer_create (void);
+
+-hb_buffer_t *
++HB_EXTERN hb_buffer_t *
+ hb_buffer_get_empty (void);
+
+-hb_buffer_t *
++HB_EXTERN hb_buffer_t *
+ hb_buffer_reference (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_destroy (hb_buffer_t *buffer);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_buffer_set_user_data (hb_buffer_t *buffer,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+-void *
++HB_EXTERN void *
+ hb_buffer_get_user_data (hb_buffer_t *buffer,
+ hb_user_data_key_t *key);
+
+-
++/**
++ * hb_buffer_content_type_t:
++ * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
++ * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
++ * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
++ */
+ typedef enum {
+ HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+ HB_BUFFER_CONTENT_TYPE_UNICODE,
+ HB_BUFFER_CONTENT_TYPE_GLYPHS
+ } hb_buffer_content_type_t;
+
+-void
++HB_EXTERN void
+ hb_buffer_set_content_type (hb_buffer_t *buffer,
+ hb_buffer_content_type_t content_type);
+
+-hb_buffer_content_type_t
++HB_EXTERN hb_buffer_content_type_t
+ hb_buffer_get_content_type (hb_buffer_t *buffer);
+
+
+-void
++HB_EXTERN void
+ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
+ hb_unicode_funcs_t *unicode_funcs);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_set_direction (hb_buffer_t *buffer,
+ hb_direction_t direction);
+
+-hb_direction_t
++HB_EXTERN hb_direction_t
+ hb_buffer_get_direction (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_set_script (hb_buffer_t *buffer,
+ hb_script_t script);
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_buffer_get_script (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_set_language (hb_buffer_t *buffer,
+ hb_language_t language);
+
+
+-hb_language_t
++HB_EXTERN hb_language_t
+ hb_buffer_get_language (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+ const hb_segment_properties_t *props);
+
+-void
++HB_EXTERN void
+ hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+ hb_segment_properties_t *props);
+
+-void
++HB_EXTERN void
+ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
++/**
++ * hb_buffer_flags_t:
++ * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
++ * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
++ * of text paragraph can be applied to this buffer. Should usually
++ * be set, unless you are passing to the buffer only part
++ * of the text without the full context.
++ * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
++ * paragraph can be applied to this buffer, similar to
++ * @HB_BUFFER_FLAG_EOT.
++ * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
++ * flag indication that character with Default_Ignorable
++ * Unicode property should use the corresponding glyph
++ * from the font, instead of hiding them (currently done
++ * by replacing them with the space glyph and zeroing the
++ * advance width.)
++ *
++ * Since: 0.9.20
++ */
+ typedef enum { /*< flags >*/
+ HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
+ HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
+@@ -178,83 +250,109 @@
+ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u
+ } hb_buffer_flags_t;
+
+-void
++HB_EXTERN void
+ hb_buffer_set_flags (hb_buffer_t *buffer,
+ hb_buffer_flags_t flags);
+
+-hb_buffer_flags_t
++HB_EXTERN hb_buffer_flags_t
+ hb_buffer_get_flags (hb_buffer_t *buffer);
+
+-
+-
++/*
++ * Since: 0.9.42
++ */
++typedef enum {
++ HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
++ HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
++ HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
++ HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
++} hb_buffer_cluster_level_t;
++
++HB_EXTERN void
++hb_buffer_set_cluster_level (hb_buffer_t *buffer,
++ hb_buffer_cluster_level_t cluster_level);
++
++HB_EXTERN hb_buffer_cluster_level_t
++hb_buffer_get_cluster_level (hb_buffer_t *buffer);
++
++/**
++ * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
++ *
++ * The default code point for replacing invalid characters in a given encoding.
++ * Set to U+FFFD REPLACEMENT CHARACTER.
++ *
++ * Since: 0.9.31
++ */
+ #define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
+
+-/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
+- * Default is 0xFFFDu. */
+-void
++HB_EXTERN void
+ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
+ hb_codepoint_t replacement);
+
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
+
+
+-/* Resets the buffer. Afterwards it's as if it was just created,
+- * except that it has a larger buffer allocated perhaps... */
+-void
++HB_EXTERN void
+ hb_buffer_reset (hb_buffer_t *buffer);
+
+-/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
+-void
++HB_EXTERN void
+ hb_buffer_clear_contents (hb_buffer_t *buffer);
+
+-/* Returns false if allocation failed */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_buffer_pre_allocate (hb_buffer_t *buffer,
+ unsigned int size);
+
+
+-/* Returns false if allocation has failed before */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_buffer_allocation_successful (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
+ hb_buffer_reverse (hb_buffer_t *buffer);
+
+-void
++HB_EXTERN void
++hb_buffer_reverse_range (hb_buffer_t *buffer,
++ unsigned int start, unsigned int end);
++
++HB_EXTERN void
+ hb_buffer_reverse_clusters (hb_buffer_t *buffer);
+
+
+ /* Filling the buffer in */
+
+-void
++HB_EXTERN void
+ hb_buffer_add (hb_buffer_t *buffer,
+ hb_codepoint_t codepoint,
+ unsigned int cluster);
+
+-void
++HB_EXTERN void
+ hb_buffer_add_utf8 (hb_buffer_t *buffer,
+ const char *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length);
+
+-void
++HB_EXTERN void
+ hb_buffer_add_utf16 (hb_buffer_t *buffer,
+ const uint16_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length);
+
+-void
++HB_EXTERN void
+ hb_buffer_add_utf32 (hb_buffer_t *buffer,
+ const uint32_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length);
+
+-/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
+-void
++HB_EXTERN void
++hb_buffer_add_latin1 (hb_buffer_t *buffer,
++ const uint8_t *text,
++ int text_length,
++ unsigned int item_offset,
++ int item_length);
++
++HB_EXTERN void
+ hb_buffer_add_codepoints (hb_buffer_t *buffer,
+ const hb_codepoint_t *text,
+ int text_length,
+@@ -262,32 +360,25 @@
+ int item_length);
+
+
+-/* Clears any new items added at the end */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_buffer_set_length (hb_buffer_t *buffer,
+ unsigned int length);
+
+-/* Return value valid as long as buffer not modified */
+-unsigned int
++HB_EXTERN unsigned int
+ hb_buffer_get_length (hb_buffer_t *buffer);
+
+ /* Getting glyphs out of the buffer */
+
+-/* Return value valid as long as buffer not modified */
+-hb_glyph_info_t *
++HB_EXTERN hb_glyph_info_t *
+ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
+ unsigned int *length);
+
+-/* Return value valid as long as buffer not modified */
+-hb_glyph_position_t *
++HB_EXTERN hb_glyph_position_t *
+ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
+ unsigned int *length);
+
+
+-/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+- * The resulting clusters should behave identical to pre-reordering clusters.
+- * NOTE: This has nothing to do with Unicode normalization. */
+-void
++HB_EXTERN void
+ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+
+@@ -295,50 +386,87 @@
+ * Serialize
+ */
+
++/**
++ * hb_buffer_serialize_flags_t:
++ * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
++ * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
++ * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
++ * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
++ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
++ *
++ * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
++ *
++ * Since: 0.9.20
++ */
+ typedef enum { /*< flags >*/
+ HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u,
+ HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
+ HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
+- HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u
++ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
++ HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u
+ } hb_buffer_serialize_flags_t;
+
++/**
++ * hb_buffer_serialize_format_t:
++ * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
++ * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
++ * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
++ *
++ * The buffer serialization and de-serialization format used in
++ * hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
++ *
++ * Since: 0.9.2
++ */
+ typedef enum {
+ HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'),
+ HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'),
+ HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
+ } hb_buffer_serialize_format_t;
+
+-/* len=-1 means str is NUL-terminated. */
+-hb_buffer_serialize_format_t
++HB_EXTERN hb_buffer_serialize_format_t
+ hb_buffer_serialize_format_from_string (const char *str, int len);
+
+-const char *
++HB_EXTERN const char *
+ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+-const char **
++HB_EXTERN const char **
+ hb_buffer_serialize_list_formats (void);
+
+-/* Returns number of items, starting at start, that were serialized. */
+-unsigned int
++HB_EXTERN unsigned int
+ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+- unsigned int *buf_consumed, /* May be NULL */
+- hb_font_t *font, /* May be NULL */
++ unsigned int *buf_consumed,
++ hb_font_t *font,
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+ const char *buf,
+- int buf_len, /* -1 means nul-terminated */
+- const char **end_ptr, /* May be NULL */
+- hb_font_t *font, /* May be NULL */
++ int buf_len,
++ const char **end_ptr,
++ hb_font_t *font,
+ hb_buffer_serialize_format_t format);
+
+
++/*
++ * Debugging.
++ */
++
++typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer,
++ hb_font_t *font,
++ const char *message,
++ void *user_data);
++
++HB_EXTERN void
++hb_buffer_set_message_func (hb_buffer_t *buffer,
++ hb_buffer_message_func_t func,
++ void *user_data, hb_destroy_func_t destroy);
++
++
+ HB_END_DECLS
+
+ #endif /* HB_BUFFER_H */
+diff -uN gfx/harfbuzz/src_old/hb-buffer-private.hh gfx/harfbuzz/src/hb-buffer-private.hh
+--- gfx/harfbuzz/src_old/hb-buffer-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer-private.hh 2016-06-05 23:48:25.604316742 +0200
+@@ -35,9 +35,37 @@
+ #include "hb-unicode-private.hh"
+
+
++#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
++#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
++#endif
++#ifndef HB_BUFFER_MAX_LEN_MIN
++#define HB_BUFFER_MAX_LEN_MIN 8192
++#endif
++#ifndef HB_BUFFER_MAX_LEN_DEFAULT
++#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
++#endif
++
+ ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
+ ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+
++HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
++HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
++
++enum hb_buffer_scratch_flags_t {
++ HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
++ HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
++ HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
++ HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
++ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE = 0x00000008u,
++ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000010u,
++ /* Reserved for complex shapers' internal use. */
++ HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
++ HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
++ HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
++ HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
++};
++HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
++
+
+ /*
+ * hb_buffer_t
+@@ -50,7 +78,10 @@
+ /* Information about how the text in the buffer should be treated */
+ hb_unicode_funcs_t *unicode; /* Unicode functions */
+ hb_buffer_flags_t flags; /* BOT / EOT / etc. */
++ hb_buffer_cluster_level_t cluster_level;
+ hb_codepoint_t replacement; /* U+FFFD or something else. */
++ hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
++ unsigned int max_len; /* Maximum allowed len. */
+
+ /* Buffer contents */
+ hb_buffer_content_type_t content_type;
+@@ -75,8 +106,8 @@
+ inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
+ inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
+
+- inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
+- inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
++ inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
++ inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
+
+ inline bool has_separate_output (void) const { return info != out_info; }
+
+@@ -93,6 +124,11 @@
+ hb_codepoint_t context[2][CONTEXT_LENGTH];
+ unsigned int context_len[2];
+
++ /* Debugging */
++ hb_buffer_message_func_t message_func;
++ void *message_data;
++ hb_destroy_func_t message_destroy;
++
+
+ /* Methods */
+
+@@ -171,9 +207,18 @@
+ unsigned int cluster_end);
+
+ HB_INTERNAL void merge_clusters (unsigned int start,
+- unsigned int end);
++ unsigned int end)
++ {
++ if (end - start < 2)
++ return;
++ merge_clusters_impl (start, end);
++ }
++ HB_INTERNAL void merge_clusters_impl (unsigned int start,
++ unsigned int end);
+ HB_INTERNAL void merge_out_clusters (unsigned int start,
+ unsigned int end);
++ /* Merge clusters for deleting current glyph, and skip it. */
++ HB_INTERNAL void delete_glyph (void);
+
+ /* Internal methods */
+ HB_INTERNAL bool enlarge (unsigned int size);
+@@ -191,6 +236,21 @@
+ HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
+
+ inline void clear_context (unsigned int side) { context_len[side] = 0; }
++
++ HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
++
++ inline bool messaging (void) { return unlikely (message_func); }
++ inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
++ {
++ if (!messaging ())
++ return true;
++ va_list ap;
++ va_start (ap, fmt);
++ bool ret = message_impl (font, fmt, ap);
++ va_end (ap);
++ return ret;
++ }
++ HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
+ };
+
+
+diff -uN gfx/harfbuzz/src_old/hb-buffer-serialize.cc gfx/harfbuzz/src/hb-buffer-serialize.cc
+--- gfx/harfbuzz/src_old/hb-buffer-serialize.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-buffer-serialize.cc 2016-06-05 23:48:26.782310166 +0200
+@@ -36,11 +36,12 @@
+ /**
+ * hb_buffer_serialize_list_formats:
+ *
+- *
++ * Returns a list of supported buffer serialization formats.
+ *
+ * Return value: (transfer none):
++ * A string array of buffer serialization formats. Should not be freed.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ const char **
+ hb_buffer_serialize_list_formats (void)
+@@ -50,14 +51,17 @@
+
+ /**
+ * hb_buffer_serialize_format_from_string:
+- * @str:
+- * @len:
++ * @str: (array length=len) (element-type uint8_t): a string to parse
++ * @len: length of @str, or -1 if string is %NULL terminated
+ *
+- *
++ * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
++ * @str is a valid buffer serialization format, use
++ * hb_buffer_serialize_list_formats() to get the list of supported formats.
+ *
+ * Return value:
++ * The parsed #hb_buffer_serialize_format_t.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_buffer_serialize_format_t
+ hb_buffer_serialize_format_from_string (const char *str, int len)
+@@ -68,13 +72,15 @@
+
+ /**
+ * hb_buffer_serialize_format_to_string:
+- * @format:
++ * @format: an #hb_buffer_serialize_format_t to convert.
+ *
+- *
++ * Converts @format to the string corresponding it, or %NULL if it is not a valid
++ * #hb_buffer_serialize_format_t.
+ *
+- * Return value:
++ * Return value: (transfer none):
++ * A %NULL terminated string corresponding to @format. Should not be freed.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ const char *
+ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+@@ -99,7 +105,8 @@
+ hb_buffer_serialize_flags_t flags)
+ {
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+- hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
++ hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
++ NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+
+ *buf_consumed = 0;
+ for (unsigned int i = start; i < end; i++)
+@@ -144,6 +151,16 @@
+ pos[i].x_advance, pos[i].y_advance);
+ }
+
++ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
++ {
++ hb_glyph_extents_t extents;
++ hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
++ extents.x_bearing, extents.y_bearing));
++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
++ extents.width, extents.height));
++ }
++
+ *p++ = '}';
+
+ unsigned int l = p - b;
+@@ -172,7 +189,8 @@
+ hb_buffer_serialize_flags_t flags)
+ {
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+- hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
++ hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
++ NULL : hb_buffer_get_glyph_positions (buffer, NULL);
+
+ *buf_consumed = 0;
+ for (unsigned int i = start; i < end; i++)
+@@ -208,6 +226,13 @@
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+ }
+
++ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
++ {
++ hb_glyph_extents_t extents;
++ hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
++ }
++
+ unsigned int l = p - b;
+ if (buf_size > l)
+ {
+@@ -223,24 +248,51 @@
+ return end - start;
+ }
+
+-/* Returns number of items, starting at start, that were serialized. */
+ /**
+ * hb_buffer_serialize_glyphs:
+- * @buffer: a buffer.
+- * @start:
+- * @end:
+- * @buf: (array length=buf_size):
+- * @buf_size:
+- * @buf_consumed: (out):
+- * @font:
+- * @format:
+- * @flags:
++ * @buffer: an #hb_buffer_t buffer.
++ * @start: the first item in @buffer to serialize.
++ * @end: the last item in @buffer to serialize.
++ * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
++ * write serialized buffer into.
++ * @buf_size: the size of @buf.
++ * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
++ * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
++ * read glyph names and extents. If %NULL, and empty font will be used.
++ * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
++ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
++ * to serialize.
++ *
++ * Serializes @buffer into a textual representation of its glyph content,
++ * useful for showing the contents of the buffer, for example during debugging.
++ * There are currently two supported serialization formats:
++ *
++ * ## text
++ * A human-readable, plain text format.
++ * The serialized glyphs will look something like:
++ *
++ * ```
++ * [uni0651=0@518,0+0|uni0628=0+1897]
++ * ```
++ * - The serialized glyphs are delimited with `[` and `]`.
++ * - Glyphs are separated with `|`
++ * - Each glyph starts with glyph name, or glyph index if
++ * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
++ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
++ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
++ * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
++ * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
++ * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
++ * #hb_glyph_extents_t in the format
++ * `&lt;x_bearing,y_bearing,width,height&gt;`
+ *
+- *
++ * ## json
++ * TODO.
+ *
+ * Return value:
++ * The number of serialized items.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ unsigned int
+ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+@@ -248,8 +300,8 @@
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+- unsigned int *buf_consumed, /* May be NULL */
+- hb_font_t *font, /* May be NULL */
++ unsigned int *buf_consumed,
++ hb_font_t *font,
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags)
+ {
+@@ -263,6 +315,9 @@
+ assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+ buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
++ if (!buffer->have_positions)
++ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
++
+ if (unlikely (start == end))
+ return 0;
+
+@@ -336,7 +391,7 @@
+
+ /**
+ * hb_buffer_deserialize_glyphs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len:
+ * @end_ptr: (out):
+@@ -347,7 +402,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+diff -uN gfx/harfbuzz/src_old/hb-common.cc gfx/harfbuzz/src/hb-common.cc
+--- gfx/harfbuzz/src_old/hb-common.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-common.cc 2016-06-05 23:48:32.151280204 +0200
+@@ -57,14 +57,14 @@
+
+ /**
+ * hb_tag_from_string:
+- * @str: (array length=len):
++ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_tag_t
+ hb_tag_from_string (const char *str, int len)
+@@ -92,7 +92,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.5
+ **/
+ void
+ hb_tag_to_string (hb_tag_t tag, char *buf)
+@@ -115,14 +115,14 @@
+
+ /**
+ * hb_direction_from_string:
+- * @str: (array length=len):
++ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_direction_t
+ hb_direction_from_string (const char *str, int len)
+@@ -149,7 +149,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ const char *
+ hb_direction_to_string (hb_direction_t direction)
+@@ -179,7 +179,7 @@
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
+ };
+
+-static hb_bool_t
++static bool
+ lang_equal (hb_language_t v1,
+ const void *v2)
+ {
+@@ -235,7 +235,7 @@
+ static hb_language_item_t *langs;
+
+ #ifdef HB_USE_ATEXIT
+-static inline
++static
+ void free_langs (void)
+ {
+ while (langs) {
+@@ -265,6 +265,7 @@
+ *lang = key;
+
+ if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
++ lang->finish ();
+ free (lang);
+ goto retry;
+ }
+@@ -280,46 +281,51 @@
+
+ /**
+ * hb_language_from_string:
+- * @str: (array length=len):
+- * @len:
++ * @str: (array length=len) (element-type uint8_t): a string representing
++ * ISO 639 language code
++ * @len: length of the @str, or -1 if it is %NULL-terminated.
+ *
+- *
++ * Converts @str representing an ISO 639 language code to the corresponding
++ * #hb_language_t.
+ *
+- * Return value:
++ * Return value: (transfer none):
++ * The #hb_language_t corresponding to the ISO 639 language code.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_language_t
+ hb_language_from_string (const char *str, int len)
+ {
+- char strbuf[64];
+-
+ if (!str || !len || !*str)
+ return HB_LANGUAGE_INVALID;
+
++ hb_language_item_t *item = NULL;
+ if (len >= 0)
+ {
+ /* NUL-terminate it. */
++ char strbuf[64];
+ len = MIN (len, (int) sizeof (strbuf) - 1);
+ memcpy (strbuf, str, len);
+ strbuf[len] = '\0';
+- str = strbuf;
++ item = lang_find_or_insert (strbuf);
+ }
+-
+- hb_language_item_t *item = lang_find_or_insert (str);
++ else
++ item = lang_find_or_insert (str);
+
+ return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
+ }
+
+ /**
+ * hb_language_to_string:
+- * @language:
++ * @language: an #hb_language_t to convert.
+ *
+- *
++ * See hb_language_from_string().
+ *
+- * Return value: (transfer none):
++ * Return value: (transfer none):
++ * A %NULL-terminated string representing the @language. Must not be freed by
++ * the caller.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ const char *
+ hb_language_to_string (hb_language_t language)
+@@ -333,9 +339,9 @@
+ *
+ *
+ *
+- * Return value:
++ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_language_t
+ hb_language_get_default (void)
+@@ -345,7 +351,7 @@
+ hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
+ if (unlikely (language == HB_LANGUAGE_INVALID)) {
+ language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+- hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
++ (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
+ }
+
+ return default_language;
+@@ -356,13 +362,14 @@
+
+ /**
+ * hb_script_from_iso15924_tag:
+- * @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:
++ * An #hb_script_t corresponding to the ISO 15924 tag.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_script_t
+ hb_script_from_iso15924_tag (hb_tag_t tag)
+@@ -400,30 +407,35 @@
+
+ /**
+ * hb_script_from_string:
+- * @s: (array length=len):
+- * @len:
+- *
+- *
++ * @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:
++ * An #hb_script_t corresponding to the ISO 15924 tag.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_script_t
+-hb_script_from_string (const char *s, int len)
++hb_script_from_string (const char *str, int len)
+ {
+- return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
++ return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
+ }
+
+ /**
+ * hb_script_to_iso15924_tag:
+- * @script:
++ * @script: an #hb_script_ to convert.
+ *
+- *
++ * See hb_script_from_iso15924_tag().
+ *
+- * Return value:
++ * Return value:
++ * An #hb_tag_t representing an ISO 15924 script tag.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_tag_t
+ hb_script_to_iso15924_tag (hb_script_t script)
+@@ -439,7 +451,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_direction_t
+ hb_script_get_horizontal_direction (hb_script_t script)
+@@ -492,6 +504,9 @@
+ case HB_SCRIPT_PALMYRENE:
+ case HB_SCRIPT_PSALTER_PAHLAVI:
+
++ /* Unicode-8.0 additions */
++ case HB_SCRIPT_OLD_HUNGARIAN:
++
+ return HB_DIRECTION_RTL;
+ }
+
+@@ -517,7 +532,7 @@
+ }
+ }
+ hb_user_data_item_t item = {key, data, destroy};
+- bool ret = !!items.replace_or_insert (item, lock, replace);
++ bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
+
+ return ret;
+ }
+@@ -541,7 +556,7 @@
+ *
+ * Returns library version as three integer components.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_version (unsigned int *major,
+@@ -560,7 +575,7 @@
+ *
+ * Return value: library version string.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ const char *
+ hb_version_string (void)
+@@ -578,7 +593,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.30
+ **/
+ hb_bool_t
+ hb_version_atleast (unsigned int major,
+diff -uN gfx/harfbuzz/src_old/hb-common.h gfx/harfbuzz/src/hb-common.h
+--- gfx/harfbuzz/src_old/hb-common.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-common.h 2016-06-05 23:48:33.399273253 +0200
+@@ -98,16 +98,22 @@
+ #define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
+
+ /* len=-1 means str is NUL-terminated. */
+-hb_tag_t
++HB_EXTERN hb_tag_t
+ hb_tag_from_string (const char *str, int len);
+
+ /* buf should have 4 bytes. */
+-void
++HB_EXTERN void
+ hb_tag_to_string (hb_tag_t tag, char *buf);
+
+
+-/* hb_direction_t */
+-
++/**
++ * hb_direction_t:
++ * @HB_DIRECTION_INVALID: Initial, unset direction.
++ * @HB_DIRECTION_LTR: Text is set horizontally from left to right.
++ * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
++ * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
++ * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
++ */
+ typedef enum {
+ HB_DIRECTION_INVALID = 0,
+ HB_DIRECTION_LTR = 4,
+@@ -117,10 +123,10 @@
+ } hb_direction_t;
+
+ /* len=-1 means str is NUL-terminated */
+-hb_direction_t
++HB_EXTERN hb_direction_t
+ hb_direction_from_string (const char *str, int len);
+
+-const char *
++HB_EXTERN const char *
+ hb_direction_to_string (hb_direction_t direction);
+
+ #define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
+@@ -136,16 +142,15 @@
+
+ typedef const struct hb_language_impl_t *hb_language_t;
+
+-/* len=-1 means str is NUL-terminated */
+-hb_language_t
++HB_EXTERN hb_language_t
+ hb_language_from_string (const char *str, int len);
+
+-const char *
++HB_EXTERN const char *
+ hb_language_to_string (hb_language_t language);
+
+ #define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
+
+-hb_language_t
++HB_EXTERN hb_language_t
+ hb_language_get_default (void);
+
+
+@@ -272,6 +277,9 @@
+ /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
+ /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
+
++ /*
++ * Since: 0.9.30
++ */
+ /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
+ /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
+ /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
+@@ -296,6 +304,13 @@
+ /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
+ /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
+
++ /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
++ /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
++ /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
++ /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
++ /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
++ /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
++
+ /* No script set. */
+ HB_SCRIPT_INVALID = HB_TAG_NONE,
+
+@@ -314,18 +329,16 @@
+
+ /* Script functions */
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_script_from_iso15924_tag (hb_tag_t tag);
+
+-/* sugar for tag_from_string() then script_from_iso15924_tag */
+-/* len=-1 means s is NUL-terminated */
+-hb_script_t
+-hb_script_from_string (const char *s, int len);
++HB_EXTERN hb_script_t
++hb_script_from_string (const char *str, int len);
+
+-hb_tag_t
++HB_EXTERN hb_tag_t
+ hb_script_to_iso15924_tag (hb_script_t script);
+
+-hb_direction_t
++HB_EXTERN hb_direction_t
+ hb_script_get_horizontal_direction (hb_script_t script);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-coretext.cc gfx/harfbuzz/src/hb-coretext.cc
+--- gfx/harfbuzz/src_old/hb-coretext.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-coretext.cc 2016-06-05 23:48:34.938264688 +0200
+@@ -22,7 +22,7 @@
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+- * GNU Author(s): Jonathan Kew
++ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+@@ -125,6 +125,9 @@
+ CFRelease (data);
+ }
+
++/*
++ * Since: 0.9.10
++ */
+ CGFontRef
+ hb_coretext_face_get_cg_font (hb_face_t *face)
+ {
+@@ -140,6 +143,7 @@
+
+ struct hb_coretext_shaper_font_data_t {
+ CTFontRef ct_font;
++ CGFloat x_mult, y_mult; /* From CT space to HB space. */
+ };
+
+ hb_coretext_shaper_font_data_t *
+@@ -154,7 +158,55 @@
+ hb_face_t *face = font->face;
+ hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+- data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL, NULL);
++ /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
++ /* TODO: use upem instead of 36? */
++ CGFloat font_size = 36.; /* Default... */
++ /* No idea if the following is even a good idea. */
++ if (font->y_ppem)
++ font_size = font->y_ppem;
++
++ if (font_size < 0)
++ font_size = -font_size;
++ data->x_mult = (CGFloat) font->x_scale / font_size;
++ data->y_mult = (CGFloat) font->y_scale / font_size;
++ data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
++ if (unlikely (!data->ct_font)) {
++ DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
++ free (data);
++ return NULL;
++ }
++
++ /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
++ * font fallback which we don't need anyway. */
++ {
++ // TODO Handle allocation failures?
++ CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0);
++ CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
++ (const void **) &last_resort,
++ 1,
++ &kCFTypeArrayCallBacks);
++ CFRelease (last_resort);
++ CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
++ (const void **) &kCTFontCascadeListAttribute,
++ (const void **) &cascade_list,
++ 1,
++ &kCFTypeDictionaryKeyCallBacks,
++ &kCFTypeDictionaryValueCallBacks);
++ CFRelease (cascade_list);
++
++ CTFontDescriptorRef new_font_desc = CTFontDescriptorCreateWithAttributes (attributes);
++ CFRelease (attributes);
++
++ CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (data->ct_font, 0.0, NULL, new_font_desc);
++ if (new_ct_font)
++ {
++ CFRelease (data->ct_font);
++ data->ct_font = new_ct_font;
++ }
++ else
++ DEBUG_MSG (CORETEXT, font, "Font copy with empty cascade list failed");
++ }
++
+ if (unlikely (!data->ct_font)) {
+ DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+ free (data);
+@@ -678,7 +730,6 @@
+ scratch += old_scratch_used;
+ scratch_size -= old_scratch_used;
+ }
+-retry:
+ {
+ string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+ pchars, chars_len,
+@@ -776,6 +827,18 @@
+
+ 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
++ */
++ 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;
++ }
+
+ const CFRange range_all = CFRangeMake (0, 0);
+
+@@ -786,6 +849,10 @@
+ status_or |= run_status;
+ status_and &= run_status;
+ DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
++ double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
++ if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
++ run_advance = -run_advance;
++ DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+
+ /* CoreText does automatic font fallback (AKA "cascading") for characters
+ * not supported by the requested font, and provides no way to turn it off,
+@@ -817,11 +884,9 @@
+ * However, even that wouldn't work if we were passed in the CGFont to
+ * begin with.
+ *
+- * Webkit uses a slightly different approach: it installs LastResort
+- * as fallback chain, and then checks PS name of used font against
+- * LastResort. That one is safe for any font except for LastResort,
+- * as opposed to ours, which can fail if we are using any uninstalled
+- * font that has the same name as an installed font.
++ * We might switch to checking PS name against "LastResort". That would
++ * be safe for all fonts except for those named "Last Resort". Might be
++ * better than what we have right now.
+ *
+ * See: http://github.com/behdad/harfbuzz/pull/36
+ */
+@@ -860,8 +925,14 @@
+ goto resize_and_retry;
+ hb_glyph_info_t *info = buffer->info + buffer->len;
+
+- CGGlyph notdef = 0;
+- double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
++ hb_codepoint_t notdef = 0;
++ hb_direction_t dir = buffer->props.direction;
++ hb_position_t x_advance, y_advance, x_offset, y_offset;
++ hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
++ hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
++ hb_position_t advance = x_advance + y_advance;
++ x_offset = -x_offset;
++ y_offset = -y_offset;
+
+ unsigned int old_len = buffer->len;
+ for (CFIndex j = range.location; j < range.location + range.length; j++)
+@@ -875,19 +946,22 @@
+ * for this one. */
+ continue;
+ }
++ if (buffer->unicode->is_default_ignorable (ch))
++ continue;
+
+ info->codepoint = notdef;
+ info->cluster = log_clusters[j];
+
+ info->mask = advance;
+- info->var1.u32 = 0;
+- info->var2.u32 = 0;
++ info->var1.i32 = x_offset;
++ info->var2.i32 = y_offset;
+
+ info++;
+ buffer->len++;
+ }
+ if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ buffer->reverse_range (old_len, buffer->len);
++ advances_so_far += run_advance;
+ continue;
+ }
+ }
+@@ -917,7 +991,7 @@
+ scratch_size = scratch_size_saved; \
+ scratch = scratch_saved;
+
+- {
++ { /* Setup glyphs */
+ SCRATCH_SAVE();
+ const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+ if (!glyphs) {
+@@ -941,6 +1015,11 @@
+ SCRATCH_RESTORE();
+ }
+ {
++ /* Setup positions.
++ * Note that CoreText does not return advances for glyphs. As such,
++ * for all but last glyph, we use the delta position to next glyph as
++ * advance (in the advance direction only), and for last glyph we set
++ * whatever is needed to make the whole run's advance add up. */
+ SCRATCH_SAVE();
+ const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+ if (!positions) {
+@@ -948,33 +1027,42 @@
+ CTRunGetPositions (run, range_all, position_buf);
+ positions = position_buf;
+ }
+- double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+- DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+ hb_glyph_info_t *info = run_info;
++ CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ {
++ hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+ for (unsigned int j = 0; j < num_glyphs; j++)
+ {
+- double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_advance) - positions[j].x;
+- info->mask = advance;
+- info->var1.u32 = positions[0].x; /* Yes, zero. */
+- info->var2.u32 = positions[j].y;
++ double advance;
++ if (likely (j + 1 < num_glyphs))
++ advance = positions[j + 1].x - positions[j].x;
++ else /* last glyph */
++ advance = run_advance - (positions[j].x - positions[0].x);
++ info->mask = advance * x_mult;
++ info->var1.i32 = x_offset;
++ info->var2.i32 = positions[j].y * y_mult;
+ info++;
+ }
+ }
+ else
+ {
+- run_advance = -run_advance;
++ hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+ for (unsigned int j = 0; j < num_glyphs; j++)
+ {
+- double advance = (j + 1 < num_glyphs ? positions[j + 1].y : positions[0].y + run_advance) - positions[j].y;
+- info->mask = advance;
+- info->var1.u32 = positions[j].x;
+- info->var2.u32 = positions[0].y; /* Yes, zero. */
++ double advance;
++ if (likely (j + 1 < num_glyphs))
++ advance = positions[j + 1].y - positions[j].y;
++ else /* last glyph */
++ advance = run_advance - (positions[j].y - positions[0].y);
++ info->mask = advance * y_mult;
++ info->var1.i32 = positions[j].x * x_mult;
++ info->var2.i32 = y_offset;
+ info++;
+ }
+ }
+ SCRATCH_RESTORE();
++ advances_so_far += run_advance;
+ }
+ #undef SCRATCH_RESTORE
+ #undef SCRATCH_SAVE
+@@ -984,10 +1072,20 @@
+ buffer->len += num_glyphs;
+ }
+
+- /* 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);
++ /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
++ * or if it does, it doesn't resepct 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
++ */
++ 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);
++ }
+
+ buffer->clear_positions ();
+
+@@ -998,16 +1096,16 @@
+ for (unsigned int i = 0; i < count; i++)
+ {
+ pos->x_advance = info->mask;
+- pos->x_offset = info->var1.u32;
+- pos->y_offset = info->var2.u32;
++ pos->x_offset = info->var1.i32;
++ pos->y_offset = info->var2.i32;
+ info++, pos++;
+ }
+ else
+ for (unsigned int i = 0; i < count; i++)
+ {
+ pos->y_advance = info->mask;
+- pos->x_offset = info->var1.u32;
+- pos->y_offset = info->var2.u32;
++ pos->x_offset = info->var1.i32;
++ pos->y_offset = info->var2.i32;
+ info++, pos++;
+ }
+
+@@ -1065,10 +1163,6 @@
+ * AAT shaper
+ */
+
+-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+-
+-
+ /*
+ * shaper face data
+ */
+diff -uN gfx/harfbuzz/src_old/hb-coretext.h gfx/harfbuzz/src/hb-coretext.h
+--- gfx/harfbuzz/src_old/hb-coretext.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-coretext.h 2016-06-05 23:48:36.098258246 +0200
+@@ -21,7 +21,7 @@
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+- * GNU Author(s): Jonathan Kew
++ * Mozilla Author(s): Jonathan Kew
+ */
+
+ #ifndef HB_CORETEXT_H
+@@ -44,14 +44,14 @@
+ #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_coretext_face_create (CGFontRef cg_font);
+
+
+-CGFontRef
++HB_EXTERN CGFontRef
+ hb_coretext_face_get_cg_font (hb_face_t *face);
+
+-CTFontRef
++HB_EXTERN CTFontRef
+ hb_coretext_font_get_ct_font (hb_font_t *font);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-directwrite.cc gfx/harfbuzz/src/hb-directwrite.cc
+--- gfx/harfbuzz/src_old/hb-directwrite.cc 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-directwrite.cc 2016-06-05 23:48:38.757243479 +0200
+@@ -0,0 +1,827 @@
++/*
++ * Copyright © 2015 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.
++ */
++
++#define HB_SHAPER directwrite
++#include "hb-shaper-impl-private.hh"
++
++#include <dwrite.h>
++
++#include "hb-directwrite.h"
++
++#include "hb-open-file-private.hh"
++#include "hb-ot-name-table.hh"
++#include "hb-ot-tag.h"
++
++
++#ifndef HB_DEBUG_DIRECTWRITE
++#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
++#endif
++
++HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
++HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
++
++/*
++* shaper face data
++*/
++
++struct hb_directwrite_shaper_face_data_t {
++ HANDLE fh;
++ wchar_t face_name[LF_FACESIZE];
++};
++
++/* face_name should point to a wchar_t[LF_FACESIZE] object. */
++static void
++_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
++{
++ /* We'll create a private name for the font from a UUID using a simple,
++ * somewhat base64-like encoding scheme */
++ const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
++ UUID id;
++ UuidCreate ((UUID*)&id);
++ ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
++ unsigned int name_str_len = 0;
++ face_name[name_str_len++] = 'F';
++ face_name[name_str_len++] = '_';
++ unsigned char *p = (unsigned char *)&id;
++ for (unsigned int i = 0; i < 16; i += 2)
++ {
++ /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
++ * using the bits in groups of 5,5,6 to select chars from enc.
++ * This will generate 24 characters; with the 'F_' prefix we already provided,
++ * the name will be 26 chars (plus the NUL terminator), so will always fit within
++ * face_name (LF_FACESIZE = 32). */
++ face_name[name_str_len++] = enc[p[i] >> 3];
++ face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
++ face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
++ }
++ face_name[name_str_len] = 0;
++ if (plen)
++ *plen = name_str_len;
++}
++
++/* Destroys blob. */
++static hb_blob_t *
++_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
++{
++ /* Create a copy of the font data, with the 'name' table replaced by a
++ * table that names the font with our private F_* name created above.
++ * For simplicity, we just append a new 'name' table and update the
++ * sfnt directory; the original table is left in place, but unused.
++ *
++ * The new table will contain just 5 name IDs: family, style, unique,
++ * full, PS. All of them point to the same name data with our unique name.
++ */
++
++ blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
++
++ unsigned int length, new_length, name_str_len;
++ const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
++
++ _hb_generate_unique_face_name (new_name, &name_str_len);
++
++ static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
++
++ unsigned int name_table_length = OT::name::min_size +
++ ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
++ name_str_len * 2; /* for name data in UTF16BE form */
++ unsigned int name_table_offset = (length + 3) & ~3;
++
++ new_length = name_table_offset + ((name_table_length + 3) & ~3);
++ void *new_sfnt_data = calloc(1, new_length);
++ if (!new_sfnt_data)
++ {
++ hb_blob_destroy (blob);
++ return NULL;
++ }
++
++ memcpy(new_sfnt_data, orig_sfnt_data, length);
++
++ OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
++ name.format.set (0);
++ name.count.set (ARRAY_LENGTH (name_IDs));
++ name.stringOffset.set (name.get_size());
++ for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
++ {
++ OT::NameRecord &record = name.nameRecord[i];
++ record.platformID.set(3);
++ record.encodingID.set(1);
++ record.languageID.set(0x0409u); /* English */
++ record.nameID.set(name_IDs[i]);
++ record.length.set(name_str_len * 2);
++ record.offset.set(0);
++ }
++
++ /* Copy string data from new_name, converting wchar_t to UTF16BE. */
++ unsigned char *p = &OT::StructAfter<unsigned char>(name);
++ for (unsigned int i = 0; i < name_str_len; i++)
++ {
++ *p++ = new_name[i] >> 8;
++ *p++ = new_name[i] & 0xff;
++ }
++
++ /* Adjust name table entry to point to new name table */
++ const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
++ unsigned int face_count = file.get_face_count ();
++ for (unsigned int face_index = 0; face_index < face_count; face_index++)
++ {
++ /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be
++ * toe-stepping. But we don't really care. */
++ const OT::OpenTypeFontFace &face = file.get_face (face_index);
++ unsigned int index;
++ if (face.find_table_index (HB_OT_TAG_name, &index))
++ {
++ OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
++ record.checkSum.set_for_data (&name, name_table_length);
++ record.offset.set (name_table_offset);
++ record.length.set (name_table_length);
++ }
++ else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
++ {
++ free (new_sfnt_data);
++ hb_blob_destroy (blob);
++ return NULL;
++ }
++ }
++
++ /* The checkSumAdjustment field in the 'head' table is now wrong,
++ * but that doesn't actually seem to cause any problems so we don't
++ * bother. */
++
++ hb_blob_destroy (blob);
++ return hb_blob_create ((const char *)new_sfnt_data, new_length,
++ HB_MEMORY_MODE_WRITABLE, NULL, free);
++}
++
++hb_directwrite_shaper_face_data_t *
++_hb_directwrite_shaper_face_data_create(hb_face_t *face)
++{
++ hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *)calloc(1, sizeof (hb_directwrite_shaper_face_data_t));
++ if (unlikely (!data))
++ return NULL;
++
++ hb_blob_t *blob = hb_face_reference_blob (face);
++ if (unlikely (!hb_blob_get_length (blob)))
++ DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
++
++ blob = _hb_rename_font (blob, data->face_name);
++ if (unlikely (!blob))
++ {
++ free(data);
++ return NULL;
++ }
++
++ DWORD num_fonts_installed;
++ data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
++ hb_blob_get_length (blob),
++ 0, &num_fonts_installed);
++ if (unlikely (!data->fh))
++ {
++ DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
++ free (data);
++ return NULL;
++ }
++
++ return data;
++}
++
++void
++_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
++{
++ RemoveFontMemResourceEx(data->fh);
++ free(data);
++}
++
++
++/*
++ * shaper font data
++ */
++
++struct hb_directwrite_shaper_font_data_t {
++ HDC hdc;
++ LOGFONTW log_font;
++ HFONT hfont;
++};
++
++static bool
++populate_log_font (LOGFONTW *lf,
++ hb_font_t *font)
++{
++ memset (lf, 0, sizeof (*lf));
++ lf->lfHeight = -font->y_scale;
++ lf->lfCharSet = DEFAULT_CHARSET;
++
++ hb_face_t *face = font->face;
++ hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
++
++ memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
++
++ return true;
++}
++
++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 NULL;
++
++ hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
++ if (unlikely (!data))
++ return NULL;
++
++ data->hdc = GetDC (NULL);
++
++ if (unlikely (!populate_log_font (&data->log_font, font))) {
++ DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
++ _hb_directwrite_shaper_font_data_destroy (data);
++ return NULL;
++ }
++
++ data->hfont = CreateFontIndirectW (&data->log_font);
++ if (unlikely (!data->hfont)) {
++ DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
++ _hb_directwrite_shaper_font_data_destroy (data);
++ return NULL;
++ }
++
++ if (!SelectObject (data->hdc, data->hfont)) {
++ DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
++ _hb_directwrite_shaper_font_data_destroy (data);
++ return NULL;
++ }
++
++ return data;
++}
++
++void
++_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
++{
++ if (data->hdc)
++ ReleaseDC (NULL, data->hdc);
++ if (data->hfont)
++ DeleteObject (data->hfont);
++ free (data);
++}
++
++LOGFONTW *
++hb_directwrite_font_get_logfontw (hb_font_t *font)
++{
++ if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
++ hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
++ return &font_data->log_font;
++}
++
++HFONT
++hb_directwrite_font_get_hfont (hb_font_t *font)
++{
++ if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
++ hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
++ return font_data->hfont;
++}
++
++
++/*
++ * shaper shape_plan data
++ */
++
++struct hb_directwrite_shaper_shape_plan_data_t {};
++
++hb_directwrite_shaper_shape_plan_data_t *
++_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
++ const hb_feature_t *user_features HB_UNUSED,
++ unsigned int num_user_features HB_UNUSED)
++{
++ return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
++}
++
++void
++_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
++{
++}
++
++// Most of here 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; }
++
++ // A single contiguous run of characters containing the same analysis
++ // results.
++ struct Run
++ {
++ UINT32 mTextStart; // starting text position of this run
++ UINT32 mTextLength; // number of contiguous code units covered
++ UINT32 mGlyphStart; // starting glyph in the glyphs array
++ UINT32 mGlyphCount; // number of glyphs associated with this run of
++ // text
++ DWRITE_SCRIPT_ANALYSIS mScript;
++ UINT8 mBidiLevel;
++ bool mIsSideways;
++
++ inline bool ContainsTextPosition(UINT32 aTextPosition) const
++ {
++ return aTextPosition >= mTextStart
++ && aTextPosition < mTextStart + mTextLength;
++ }
++
++ Run *nextRun;
++ };
++
++public:
++ TextAnalysis(const wchar_t* text,
++ UINT32 textLength,
++ const wchar_t* localeName,
++ DWRITE_READING_DIRECTION readingDirection)
++ : mText(text)
++ , mTextLength(textLength)
++ , mLocaleName(localeName)
++ , mReadingDirection(readingDirection)
++ , mCurrentRun(NULL) { };
++
++ ~TextAnalysis() {
++ // delete runs, except mRunHead which is part of the TextAnalysis object
++ for (Run *run = mRunHead.nextRun; run;) {
++ Run *origRun = run;
++ run = run->nextRun;
++ delete origRun;
++ }
++ }
++
++ 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 = NULL;
++ mCurrentRun = &mRunHead;
++
++ // Call each of the analyzers in sequence, recording their results.
++ if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
++ 0,
++ mTextLength,
++ this))) {
++ *runHead = &mRunHead;
++ }
++
++ return hr;
++ }
++
++ // IDWriteTextAnalysisSource implementation
++
++ IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
++ OUT WCHAR const** textString,
++ OUT UINT32* textLength)
++ {
++ if (textPosition >= mTextLength) {
++ // No text at this position, valid query though.
++ *textString = NULL;
++ *textLength = 0;
++ }
++ else {
++ *textString = mText + textPosition;
++ *textLength = mTextLength - textPosition;
++ }
++ return S_OK;
++ }
++
++ IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
++ OUT WCHAR const** textString,
++ OUT UINT32* textLength)
++ {
++ if (textPosition == 0 || textPosition > mTextLength) {
++ // Either there is no text before here (== 0), or this
++ // is an invalid position. The query is considered valid thouh.
++ *textString = NULL;
++ *textLength = 0;
++ }
++ else {
++ *textString = mText;
++ *textLength = textPosition;
++ }
++ return S_OK;
++ }
++
++ IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
++ GetParagraphReadingDirection() { return mReadingDirection; }
++
++ IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
++ UINT32* textLength,
++ WCHAR const** localeName) {
++ return S_OK;
++ }
++
++ IFACEMETHODIMP
++ GetNumberSubstitution(UINT32 textPosition,
++ OUT UINT32* textLength,
++ OUT IDWriteNumberSubstitution** numberSubstitution)
++ {
++ // We do not support number substitution.
++ *numberSubstitution = NULL;
++ *textLength = mTextLength - textPosition;
++
++ return S_OK;
++ }
++
++ // IDWriteTextAnalysisSink implementation
++
++ IFACEMETHODIMP
++ SetScriptAnalysis(UINT32 textPosition,
++ UINT32 textLength,
++ DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
++ {
++ SetCurrentRun(textPosition);
++ SplitCurrentRun(textPosition);
++ while (textLength > 0) {
++ Run *run = FetchNextRun(&textLength);
++ run->mScript = *scriptAnalysis;
++ }
++
++ return S_OK;
++ }
++
++ IFACEMETHODIMP
++ SetLineBreakpoints(UINT32 textPosition,
++ UINT32 textLength,
++ const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
++
++ IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
++ UINT32 textLength,
++ UINT8 explicitLevel,
++ UINT8 resolvedLevel) { return S_OK; }
++
++ IFACEMETHODIMP
++ SetNumberSubstitution(UINT32 textPosition,
++ UINT32 textLength,
++ IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
++
++protected:
++ Run *FetchNextRun(IN OUT UINT32* 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 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) {
++ if (run->ContainsTextPosition(textPosition)) {
++ mCurrentRun = run;
++ return;
++ }
++ }
++ //NS_NOTREACHED("We should always be able to find the text position in one \
++ // of our runs");
++ }
++
++ void SplitCurrentRun(UINT32 splitPosition)
++ {
++ if (!mCurrentRun) {
++ //NS_ASSERTION(false, "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 = 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.
++ UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
++ newRun->mTextStart += splitPoint;
++ newRun->mTextLength -= splitPoint;
++ mCurrentRun->mTextLength = splitPoint;
++ mCurrentRun = newRun;
++ }
++
++protected:
++ // Input
++ // (weak references are fine here, since this class is a transient
++ // stack-based helper that doesn't need to copy data)
++ UINT32 mTextLength;
++ const WCHAR* mText;
++ const WCHAR* mLocaleName;
++ DWRITE_READING_DIRECTION mReadingDirection;
++
++ // Current processing state.
++ Run *mCurrentRun;
++
++ // Output is a list of runs starting here
++ Run mRunHead;
++};
++
++
++/*
++ * shaper
++ */
++
++hb_bool_t
++_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)
++{
++ 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);
++
++ // factory probably should be cached
++ IDWriteFactory* dwriteFactory;
++ DWriteCreateFactory(
++ DWRITE_FACTORY_TYPE_SHARED,
++ __uuidof(IDWriteFactory),
++ reinterpret_cast<IUnknown**>(&dwriteFactory)
++ );
++
++ IDWriteGdiInterop *gdiInterop;
++ dwriteFactory->GetGdiInterop (&gdiInterop);
++ IDWriteFontFace* fontFace;
++ gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
++
++ IDWriteTextAnalyzer* 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, pchars, 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))
++ pchars[chars_len++] = c;
++ else if (unlikely(c > 0x10FFFFu))
++ pchars[chars_len++] = 0xFFFDu;
++ else {
++ pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
++ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
++ }
++ }
++
++ ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
++ if (num_features)
++ {
++ /* 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. */
++ }
++ }
++
++ HRESULT hr;
++ // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
++
++ 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 length = buffer->len;
++
++ TextAnalysis analysis(pchars, length, NULL, readingDirection);
++ TextAnalysis::Run *runHead;
++ hr = analysis.GenerateResults(analyzer, &runHead);
++
++ if (FAILED(hr)) {
++ //NS_WARNING("Analyzer failed to generate results.");
++ return false;
++ }
++
++ UINT32 maxGlyphs = 3 * length / 2 + 16;
++
++#define INITIAL_GLYPH_SIZE 400
++ UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
++ UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
++ DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
++ DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
++
++ UINT32 actualGlyphs;
++
++ bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction);
++
++ wchar_t lang[4];
++ mbstowcs(lang, hb_language_to_string(buffer->props.language), 4);
++ hr = analyzer->GetGlyphs(pchars, length,
++ fontFace, FALSE,
++ buffer->props.direction,
++ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
++ maxGlyphs, clusters, textProperties,
++ glyphs, glyphProperties, &actualGlyphs);
++
++ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
++ free(clusters);
++ free(glyphs);
++ free(textProperties);
++ free(glyphProperties);
++
++ clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
++ glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
++ textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
++ glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
++
++ hr = analyzer->GetGlyphs(pchars, length,
++ fontFace, FALSE,
++ buffer->props.direction,
++ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
++ maxGlyphs, clusters, textProperties,
++ glyphs, glyphProperties, &actualGlyphs);
++ }
++ if (FAILED(hr)) {
++ //NS_WARNING("Analyzer failed to get glyphs.");
++ return false;
++ }
++
++ FLOAT advances[400];
++ DWRITE_GLYPH_OFFSET offsets[400];
++
++
++ /* 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) +
++ 4 + // sizeof (SCRIPT_GLYPHPROP) +
++ sizeof (int) +
++ 8 + // sizeof (GOFFSET) +
++ sizeof (uint32_t));
++ ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size);
++
++#undef ALLOCATE_ARRAY
++
++ hr = analyzer->GetGlyphPlacements(pchars,
++ clusters,
++ textProperties,
++ length,
++ glyphs,
++ glyphProperties,
++ actualGlyphs,
++ fontFace,
++ face->get_upem(),
++ FALSE,
++ FALSE,
++ &runHead->mScript,
++ NULL,
++ NULL,
++ NULL,
++ 0,
++ advances,
++ offsets);
++
++ if (FAILED(hr)) {
++ //NS_WARNING("Analyzer failed to get glyph placements.");
++ return false;
++ }
++
++ unsigned int glyphs_len = actualGlyphs;
++
++ /* 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 < glyphs_len; 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()]];
++ //*p = MIN (*p, buffer->info[i].cluster);
++ }
++ for (unsigned int i = 1; i < glyphs_len; i++)
++ if (vis_clusters[i] == -1)
++ vis_clusters[i] = vis_clusters[i - 1];
++
++#undef utf16_index
++
++ //if (unlikely (!buffer->ensure (glyphs_len)))
++ // FAIL ("Buffer in error");
++
++#undef FAIL
++
++ /* Set glyph infos */
++ buffer->len = 0;
++ for (unsigned int i = 0; i < glyphs_len; i++)
++ {
++ hb_glyph_info_t *info = &buffer->info[buffer->len++];
++
++ info->codepoint = glyphs[i];
++ info->cluster = vis_clusters[i];
++
++ /* The rest is crap. Let's store position info there for now. */
++ info->mask = advances[i];
++ info->var1.u32 = offsets[i].ascenderOffset;
++ info->var2.u32 = -offsets[i].advanceOffset;
++ }
++
++ free(clusters);
++ free(glyphs);
++ free(textProperties);
++ free(glyphProperties);
++
++ /* Set glyph positions */
++ buffer->clear_positions ();
++ for (unsigned int i = 0; i < glyphs_len; i++)
++ {
++ hb_glyph_info_t *info = &buffer->info[i];
++ hb_glyph_position_t *pos = &buffer->pos[i];
++
++ /* TODO vertical */
++ pos->x_advance = info->mask;
++ pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
++ pos->y_offset = info->var2.u32;
++ }
++
++ if (backward)
++ hb_buffer_reverse (buffer);
++
++ /* Wow, done! */
++ return true;
++}
+diff -uN gfx/harfbuzz/src_old/hb-directwrite.h gfx/harfbuzz/src/hb-directwrite.h
+--- gfx/harfbuzz/src_old/hb-directwrite.h 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-directwrite.h 2016-06-05 23:48:40.059236276 +0200
+@@ -0,0 +1,34 @@
++/*
++ * Copyright © 2015 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_DIRECTWRITE_H
++#define HB_DIRECTWRITE_H
++
++#include "hb.h"
++
++HB_BEGIN_DECLS
++
++HB_END_DECLS
++
++#endif /* HB_UNISCRIBE_H */
+diff -uN gfx/harfbuzz/src_old/hb-face.cc gfx/harfbuzz/src/hb-face.cc
+--- gfx/harfbuzz/src_old/hb-face.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-face.cc 2016-06-05 23:48:42.449223049 +0200
+@@ -77,7 +77,7 @@
+ *
+ * Return value: (transfer full)
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
+@@ -113,7 +113,7 @@
+ {
+ hb_face_for_data_closure_t *closure;
+
+- closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
++ closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
+ if (unlikely (!closure))
+ return NULL;
+
+@@ -157,7 +157,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_face_create (hb_blob_t *blob,
+@@ -165,8 +165,8 @@
+ {
+ hb_face_t *face;
+
+- if (unlikely (!blob || !hb_blob_get_length (blob)))
+- return hb_face_get_empty ();
++ if (unlikely (!blob))
++ blob = hb_blob_get_empty ();
+
+ hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+
+@@ -189,7 +189,7 @@
+ *
+ * Return value: (transfer full)
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_face_get_empty (void)
+@@ -206,7 +206,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_face_reference (hb_face_t *face)
+@@ -220,7 +220,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_face_destroy (hb_face_t *face)
+@@ -257,7 +257,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_face_set_user_data (hb_face_t *face,
+@@ -278,7 +278,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_face_get_user_data (hb_face_t *face,
+@@ -293,7 +293,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_face_make_immutable (hb_face_t *face)
+@@ -312,7 +312,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_face_is_immutable (hb_face_t *face)
+@@ -330,7 +330,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_face_reference_table (hb_face_t *face,
+@@ -347,7 +347,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_blob_t *
+ hb_face_reference_blob (hb_face_t *face)
+@@ -362,7 +362,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_face_set_index (hb_face_t *face,
+@@ -382,7 +382,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ unsigned int
+ hb_face_get_index (hb_face_t *face)
+@@ -397,7 +397,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_face_set_upem (hb_face_t *face,
+@@ -417,7 +417,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ unsigned int
+ hb_face_get_upem (hb_face_t *face)
+@@ -441,7 +441,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_face_set_glyph_count (hb_face_t *face,
+@@ -461,7 +461,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ unsigned int
+ hb_face_get_glyph_count (hb_face_t *face)
+diff -uN gfx/harfbuzz/src_old/hb-face.h gfx/harfbuzz/src/hb-face.h
+--- gfx/harfbuzz/src_old/hb-face.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-face.h 2016-06-05 23:48:43.669216308 +0200
+@@ -43,28 +43,28 @@
+
+ typedef struct hb_face_t hb_face_t;
+
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_face_create (hb_blob_t *blob,
+ unsigned int index);
+
+ typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
+
+ /* calls destroy() when not needing user_data anymore */
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
+ void *user_data,
+ hb_destroy_func_t destroy);
+
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_face_get_empty (void);
+
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_face_reference (hb_face_t *face);
+
+-void
++HB_EXTERN void
+ hb_face_destroy (hb_face_t *face);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_face_set_user_data (hb_face_t *face,
+ hb_user_data_key_t *key,
+ void * data,
+@@ -72,43 +72,43 @@
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_face_get_user_data (hb_face_t *face,
+ hb_user_data_key_t *key);
+
+-void
++HB_EXTERN void
+ hb_face_make_immutable (hb_face_t *face);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_face_is_immutable (hb_face_t *face);
+
+
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_face_reference_table (hb_face_t *face,
+ hb_tag_t tag);
+
+-hb_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_face_reference_blob (hb_face_t *face);
+
+-void
++HB_EXTERN void
+ hb_face_set_index (hb_face_t *face,
+ unsigned int index);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_face_get_index (hb_face_t *face);
+
+-void
++HB_EXTERN void
+ hb_face_set_upem (hb_face_t *face,
+ unsigned int upem);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_face_get_upem (hb_face_t *face);
+
+-void
++HB_EXTERN void
+ hb_face_set_glyph_count (hb_face_t *face,
+ unsigned int glyph_count);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_face_get_glyph_count (hb_face_t *face);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-fallback-shape.cc gfx/harfbuzz/src/hb-fallback-shape.cc
+--- gfx/harfbuzz/src_old/hb-fallback-shape.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-fallback-shape.cc 2016-06-05 23:48:44.900209512 +0200
+@@ -106,7 +106,7 @@
+ */
+
+ hb_codepoint_t space;
+- bool has_space = font->get_glyph (' ', 0, &space);
++ bool has_space = (bool) font->get_glyph (' ', 0, &space);
+
+ buffer->clear_positions ();
+
+diff -uN gfx/harfbuzz/src_old/hb-font.cc gfx/harfbuzz/src/hb-font.cc
+--- gfx/harfbuzz/src_old/hb-font.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-font.cc 2016-06-05 23:48:47.920192879 +0200
+@@ -45,130 +45,224 @@
+ */
+
+ static hb_bool_t
+-hb_font_get_glyph_nil (hb_font_t *font,
++hb_font_get_font_h_extents_nil (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ memset (metrics, 0, sizeof (*metrics));
++ return false;
++}
++static hb_bool_t
++hb_font_get_font_h_extents_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_font_h_extents (metrics);
++ if (ret) {
++ metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
++ metrics->descender = font->parent_scale_y_distance (metrics->descender);
++ metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
++ }
++ return ret;
++}
++
++static hb_bool_t
++hb_font_get_font_v_extents_nil (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ memset (metrics, 0, sizeof (*metrics));
++ return false;
++}
++static hb_bool_t
++hb_font_get_font_v_extents_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_font_v_extents (metrics);
++ if (ret) {
++ metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
++ metrics->descender = font->parent_scale_x_distance (metrics->descender);
++ metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
++ }
++ return ret;
++}
++
++static hb_bool_t
++hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent->get_glyph (unicode, variation_selector, glyph);
+-
+ *glyph = 0;
+ return false;
+ }
++static hb_bool_t
++hb_font_get_glyph_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t unicode,
++ hb_codepoint_t variation_selector,
++ hb_codepoint_t *glyph,
++ void *user_data HB_UNUSED)
++{
++ return font->parent->get_glyph (unicode, variation_selector, glyph);
++}
+
+ static hb_position_t
+-hb_font_get_glyph_h_advance_nil (hb_font_t *font,
++hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+-
+ 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_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+-
+ return font->y_scale;
+ }
++static hb_position_t
++hb_font_get_glyph_v_advance_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ void *user_data HB_UNUSED)
++{
++ return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
++}
+
+ static hb_bool_t
+-hb_font_get_glyph_h_origin_nil (hb_font_t *font,
++hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent) {
+- hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+- if (ret)
+- font->parent_scale_position (x, y);
+- return ret;
+- }
+-
+ *x = *y = 0;
+- return false;
++ return true;
++}
++static hb_bool_t
++hb_font_get_glyph_h_origin_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ hb_position_t *x,
++ hb_position_t *y,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
++ if (ret)
++ font->parent_scale_position (x, y);
++ return ret;
+ }
+
+ static hb_bool_t
+-hb_font_get_glyph_v_origin_nil (hb_font_t *font,
++hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent) {
+- hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+- if (ret)
+- font->parent_scale_position (x, y);
+- return ret;
+- }
+-
+ *x = *y = 0;
+ return false;
+ }
++static hb_bool_t
++hb_font_get_glyph_v_origin_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ hb_position_t *x,
++ hb_position_t *y,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
++ if (ret)
++ font->parent_scale_position (x, y);
++ return ret;
++}
+
+ static hb_position_t
+-hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
++hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t left_glyph,
+ hb_codepoint_t right_glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+-
+ return 0;
+ }
++static hb_position_t
++hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t left_glyph,
++ hb_codepoint_t right_glyph,
++ void *user_data HB_UNUSED)
++{
++ return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
++}
+
+ static hb_position_t
+-hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
++hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t top_glyph,
+ hb_codepoint_t bottom_glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+-
+ return 0;
+ }
++static hb_position_t
++hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t top_glyph,
++ hb_codepoint_t bottom_glyph,
++ void *user_data HB_UNUSED)
++{
++ return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
++}
+
+ static hb_bool_t
+-hb_font_get_glyph_extents_nil (hb_font_t *font,
++hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent) {
+- hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+- if (ret) {
+- font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+- font->parent_scale_distance (&extents->width, &extents->height);
+- }
+- return ret;
+- }
+-
+ memset (extents, 0, sizeof (*extents));
+ return false;
+ }
++static hb_bool_t
++hb_font_get_glyph_extents_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ hb_glyph_extents_t *extents,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
++ if (ret) {
++ font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
++ font->parent_scale_distance (&extents->width, &extents->height);
++ }
++ return ret;
++}
+
+ static hb_bool_t
+-hb_font_get_glyph_contour_point_nil (hb_font_t *font,
++hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ unsigned int point_index,
+@@ -176,45 +270,63 @@
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent) {
+- hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+- if (ret)
+- font->parent_scale_position (x, y);
+- return ret;
+- }
+-
+ *x = *y = 0;
+ return false;
+ }
++static hb_bool_t
++hb_font_get_glyph_contour_point_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ unsigned int point_index,
++ hb_position_t *x,
++ hb_position_t *y,
++ void *user_data HB_UNUSED)
++{
++ hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
++ if (ret)
++ font->parent_scale_position (x, y);
++ return ret;
++}
+
+ static hb_bool_t
+-hb_font_get_glyph_name_nil (hb_font_t *font,
++hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ char *name, unsigned int size,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent->get_glyph_name (glyph, name, size);
+-
+ if (size) *name = '\0';
+ return false;
+ }
++static hb_bool_t
++hb_font_get_glyph_name_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ hb_codepoint_t glyph,
++ char *name, unsigned int size,
++ void *user_data HB_UNUSED)
++{
++ return font->parent->get_glyph_name (glyph, name, size);
++}
+
+ static hb_bool_t
+-hb_font_get_glyph_from_name_nil (hb_font_t *font,
++hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+ {
+- if (font->parent)
+- return font->parent->get_glyph_from_name (name, len, glyph);
+-
+ *glyph = 0;
+ return false;
+ }
+-
++static hb_bool_t
++hb_font_get_glyph_from_name_parent (hb_font_t *font,
++ void *font_data HB_UNUSED,
++ const char *name, int len, /* -1 means nul-terminated */
++ hb_codepoint_t *glyph,
++ void *user_data HB_UNUSED)
++{
++ return font->parent->get_glyph_from_name (name, len, glyph);
++}
+
+ static const hb_font_funcs_t _hb_font_funcs_nil = {
+ HB_OBJECT_HEADER_STATIC,
+@@ -222,9 +334,44 @@
+ true, /* immutable */
+
+ {
++#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++ },
++ {
++#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++ },
++ {
++ {
+ #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++ }
++ }
++};
++static const hb_font_funcs_t _hb_font_funcs_parent = {
++ HB_OBJECT_HEADER_STATIC,
++
++ true, /* immutable */
++
++ {
++#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++ },
++ {
++#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+ #undef HB_FONT_FUNC_IMPLEMENT
++ },
++ {
++ {
++#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++ }
+ }
+ };
+
+@@ -236,7 +383,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_funcs_t *
+ hb_font_funcs_create (void)
+@@ -246,7 +393,7 @@
+ if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
+ return hb_font_funcs_get_empty ();
+
+- ffuncs->get = _hb_font_funcs_nil.get;
++ ffuncs->get = _hb_font_funcs_parent.get;
+
+ return ffuncs;
+ }
+@@ -258,12 +405,12 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_funcs_t *
+ hb_font_funcs_get_empty (void)
+ {
+- return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
++ return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
+ }
+
+ /**
+@@ -274,7 +421,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_funcs_t *
+ hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
+@@ -288,7 +435,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
+@@ -315,7 +462,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
+@@ -336,7 +483,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
+@@ -352,7 +499,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
+@@ -371,7 +518,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
+@@ -398,11 +545,11 @@
+ ffuncs->destroy.name (ffuncs->user_data.name); \
+ \
+ if (func) { \
+- ffuncs->get.name = func; \
++ ffuncs->get.f.name = func; \
+ ffuncs->user_data.name = user_data; \
+ ffuncs->destroy.name = destroy; \
+ } else { \
+- ffuncs->get.name = hb_font_get_##name##_nil; \
++ ffuncs->get.f.name = hb_font_get_##name##_parent; \
+ ffuncs->user_data.name = NULL; \
+ ffuncs->destroy.name = NULL; \
+ } \
+@@ -411,10 +558,53 @@
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+ #undef HB_FONT_FUNC_IMPLEMENT
+
++bool
++hb_font_t::has_func (unsigned int i)
++{
++ if (parent && parent != hb_font_get_empty () && parent->has_func (i))
++ return true;
++ return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
++}
+
+ /* Public getters */
+
+ /**
++ * hb_font_get_h_extents:
++ * @font: a font.
++ * @extents: (out):
++ *
++ *
++ *
++ * Return value:
++ *
++ * Since: 1.1.3
++ **/
++hb_bool_t
++hb_font_get_h_extents (hb_font_t *font,
++ hb_font_extents_t *extents)
++{
++ return font->get_font_h_extents (extents);
++}
++
++/**
++ * hb_font_get_v_extents:
++ * @font: a font.
++ * @extents: (out):
++ *
++ *
++ *
++ * Return value:
++ *
++ * Since: 1.1.3
++ **/
++hb_bool_t
++hb_font_get_v_extents (hb_font_t *font,
++ hb_font_extents_t *extents)
++{
++ return font->get_font_v_extents (extents);
++}
++
++/**
+ * hb_font_get_glyph:
+ * @font: a font.
+ * @unicode:
+@@ -425,7 +615,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph (hb_font_t *font,
+@@ -444,7 +634,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_position_t
+ hb_font_get_glyph_h_advance (hb_font_t *font,
+@@ -462,7 +652,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_position_t
+ hb_font_get_glyph_v_advance (hb_font_t *font,
+@@ -482,7 +672,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_h_origin (hb_font_t *font,
+@@ -503,7 +693,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_v_origin (hb_font_t *font,
+@@ -523,7 +713,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_position_t
+ hb_font_get_glyph_h_kerning (hb_font_t *font,
+@@ -542,7 +732,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_position_t
+ hb_font_get_glyph_v_kerning (hb_font_t *font,
+@@ -561,7 +751,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_extents (hb_font_t *font,
+@@ -583,7 +773,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_contour_point (hb_font_t *font,
+@@ -604,7 +794,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_name (hb_font_t *font,
+@@ -625,7 +815,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_from_name (hb_font_t *font,
+@@ -639,6 +829,23 @@
+ /* A bit higher-level, and with fallback */
+
+ /**
++ * hb_font_get_extents_for_direction:
++ * @font: a font.
++ * @direction:
++ * @extents:
++ *
++ *
++ *
++ * Since: 1.1.3
++ **/
++void
++hb_font_get_extents_for_direction (hb_font_t *font,
++ hb_direction_t direction,
++ hb_font_extents_t *extents)
++{
++ return font->get_extents_for_direction (direction, extents);
++}
++/**
+ * hb_font_get_glyph_advance_for_direction:
+ * @font: a font.
+ * @glyph:
+@@ -648,7 +855,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
+@@ -669,7 +876,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_get_glyph_origin_for_direction (hb_font_t *font,
+@@ -690,7 +897,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
+@@ -711,7 +918,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
+@@ -733,7 +940,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
+@@ -755,7 +962,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
+@@ -779,7 +986,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
+@@ -800,7 +1007,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_glyph_to_string (hb_font_t *font,
+@@ -814,7 +1021,7 @@
+ /**
+ * hb_font_glyph_from_string:
+ * @font: a font.
+- * @s: (array length=len):
++ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ * @glyph: (out):
+ *
+@@ -822,7 +1029,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_glyph_from_string (hb_font_t *font,
+@@ -845,7 +1052,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_font_create (hb_face_t *face)
+@@ -854,15 +1061,16 @@
+
+ if (unlikely (!face))
+ face = hb_face_get_empty ();
+- if (unlikely (hb_object_is_inert (face)))
+- return hb_font_get_empty ();
+ if (!(font = hb_object_create<hb_font_t> ()))
+ return hb_font_get_empty ();
+
+ hb_face_make_immutable (face);
++ font->parent = hb_font_get_empty ();
+ font->face = hb_face_reference (face);
+ font->klass = hb_font_funcs_get_empty ();
+
++ font->x_scale = font->y_scale = hb_face_get_upem (face);
++
+ return font;
+ }
+
+@@ -874,20 +1082,19 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_font_create_sub_font (hb_font_t *parent)
+ {
+ if (unlikely (!parent))
+- return hb_font_get_empty ();
++ parent = hb_font_get_empty ();
+
+ hb_font_t *font = hb_font_create (parent->face);
+
+ if (unlikely (hb_object_is_inert (font)))
+ return font;
+
+- hb_font_make_immutable (parent);
+ font->parent = hb_font_reference (parent);
+
+ font->x_scale = parent->x_scale;
+@@ -905,7 +1112,7 @@
+ *
+ * Return value: (transfer full)
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_font_get_empty (void)
+@@ -918,8 +1125,8 @@
+ NULL, /* parent */
+ const_cast<hb_face_t *> (&_hb_face_nil),
+
+- 0, /* x_scale */
+- 0, /* y_scale */
++ 1000, /* x_scale */
++ 1000, /* y_scale */
+
+ 0, /* x_ppem */
+ 0, /* y_ppem */
+@@ -946,7 +1153,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_font_reference (hb_font_t *font)
+@@ -960,7 +1167,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_destroy (hb_font_t *font)
+@@ -993,7 +1200,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_set_user_data (hb_font_t *font,
+@@ -1014,7 +1221,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_font_get_user_data (hb_font_t *font,
+@@ -1029,7 +1236,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_make_immutable (hb_font_t *font)
+@@ -1037,6 +1244,9 @@
+ if (unlikely (hb_object_is_inert (font)))
+ return;
+
++ if (font->parent)
++ hb_font_make_immutable (font->parent);
++
+ font->immutable = true;
+ }
+
+@@ -1048,7 +1258,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_font_is_immutable (hb_font_t *font)
+@@ -1057,6 +1267,32 @@
+ }
+
+ /**
++ * hb_font_set_parent:
++ * @font: a font.
++ * @parent: new parent.
++ *
++ * Sets parent font of @font.
++ *
++ * Since: 1.0.5
++ **/
++void
++hb_font_set_parent (hb_font_t *font,
++ hb_font_t *parent)
++{
++ if (font->immutable)
++ return;
++
++ if (!parent)
++ parent = hb_font_get_empty ();
++
++ hb_font_t *old = font->parent;
++
++ font->parent = hb_font_reference (parent);
++
++ hb_font_destroy (old);
++}
++
++/**
+ * hb_font_get_parent:
+ * @font: a font.
+ *
+@@ -1064,7 +1300,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_font_get_parent (hb_font_t *font)
+@@ -1080,7 +1316,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_font_get_face (hb_font_t *font)
+@@ -1098,7 +1334,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_set_funcs (hb_font_t *font,
+@@ -1133,7 +1369,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_set_funcs_data (hb_font_t *font,
+@@ -1163,7 +1399,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_set_scale (hb_font_t *font,
+@@ -1185,7 +1421,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_get_scale (hb_font_t *font,
+@@ -1204,7 +1440,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_set_ppem (hb_font_t *font,
+@@ -1226,7 +1462,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_font_get_ppem (hb_font_t *font,
+diff -uN gfx/harfbuzz/src_old/hb-font.h gfx/harfbuzz/src/hb-font.h
+--- gfx/harfbuzz/src_old/hb-font.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-font.h 2016-06-05 23:48:49.311185210 +0200
+@@ -46,19 +46,19 @@
+
+ typedef struct hb_font_funcs_t hb_font_funcs_t;
+
+-hb_font_funcs_t *
++HB_EXTERN hb_font_funcs_t *
+ hb_font_funcs_create (void);
+
+-hb_font_funcs_t *
++HB_EXTERN hb_font_funcs_t *
+ hb_font_funcs_get_empty (void);
+
+-hb_font_funcs_t *
++HB_EXTERN hb_font_funcs_t *
+ hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
+
+-void
++HB_EXTERN void
+ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key,
+ void * data,
+@@ -66,31 +66,56 @@
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key);
+
+
+-void
++HB_EXTERN void
+ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
+
+
+-/* glyph extents */
++/* font and glyph extents */
+
++/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
++typedef struct hb_font_extents_t
++{
++ hb_position_t ascender; /* typographic ascender. */
++ hb_position_t descender; /* typographic descender. */
++ hb_position_t line_gap; /* suggested line spacing gap. */
++ /*< private >*/
++ hb_position_t reserved9;
++ hb_position_t reserved8;
++ hb_position_t reserved7;
++ hb_position_t reserved6;
++ hb_position_t reserved5;
++ hb_position_t reserved4;
++ hb_position_t reserved3;
++ hb_position_t reserved2;
++ hb_position_t reserved1;
++} hb_font_extents_t;
++
++/* Note that height is negative in coordinate systems that grow up. */
+ typedef struct hb_glyph_extents_t
+ {
+- hb_position_t x_bearing;
+- hb_position_t y_bearing;
+- hb_position_t width;
+- hb_position_t height;
++ hb_position_t x_bearing; /* left side of glyph from origin. */
++ hb_position_t y_bearing; /* top side of glyph from origin. */
++ hb_position_t width; /* distance from left to right side. */
++ hb_position_t height; /* distance from top to bottom side. */
+ } hb_glyph_extents_t;
+
+-
+ /* func types */
+
++typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
++ hb_font_extents_t *metrics,
++ void *user_data);
++typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
++typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
++
++
+ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+@@ -140,6 +165,38 @@
+ /* func setters */
+
+ /**
++ * hb_font_funcs_set_font_h_extents_func:
++ * @ffuncs: font functions.
++ * @func: (closure user_data) (destroy destroy) (scope notified):
++ * @user_data:
++ * @destroy:
++ *
++ *
++ *
++ * Since: 1.1.2
++ **/
++HB_EXTERN void
++hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
++ hb_font_get_font_h_extents_func_t func,
++ void *user_data, hb_destroy_func_t destroy);
++
++/**
++ * hb_font_funcs_set_font_v_extents_func:
++ * @ffuncs: font functions.
++ * @func: (closure user_data) (destroy destroy) (scope notified):
++ * @user_data:
++ * @destroy:
++ *
++ *
++ *
++ * Since: 1.1.2
++ **/
++HB_EXTERN void
++hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
++ hb_font_get_font_v_extents_func_t func,
++ void *user_data, hb_destroy_func_t destroy);
++
++/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+@@ -148,9 +205,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -164,9 +221,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_h_advance_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -180,9 +237,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_v_advance_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -196,9 +253,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_h_origin_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -212,9 +269,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_v_origin_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -228,9 +285,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_h_kerning_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -244,9 +301,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_v_kerning_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -260,9 +317,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_extents_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -276,9 +333,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_contour_point_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -292,9 +349,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_name_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -308,59 +365,65 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_from_name_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+-
+ /* func dispatch */
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
++hb_font_get_h_extents (hb_font_t *font,
++ hb_font_extents_t *extents);
++HB_EXTERN hb_bool_t
++hb_font_get_v_extents (hb_font_t *font,
++ hb_font_extents_t *extents);
++
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph (hb_font_t *font,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph);
+
+-hb_position_t
++HB_EXTERN hb_position_t
+ hb_font_get_glyph_h_advance (hb_font_t *font,
+ hb_codepoint_t glyph);
+-hb_position_t
++HB_EXTERN hb_position_t
+ hb_font_get_glyph_v_advance (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_h_origin (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y);
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_v_origin (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y);
+
+-hb_position_t
++HB_EXTERN hb_position_t
+ hb_font_get_glyph_h_kerning (hb_font_t *font,
+ hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+-hb_position_t
++HB_EXTERN hb_position_t
+ hb_font_get_glyph_v_kerning (hb_font_t *font,
+ hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_extents (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_contour_point (hb_font_t *font,
+ hb_codepoint_t glyph, unsigned int point_index,
+ hb_position_t *x, hb_position_t *y);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_name (hb_font_t *font,
+ hb_codepoint_t glyph,
+ char *name, unsigned int size);
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_from_name (hb_font_t *font,
+ const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph);
+@@ -368,52 +431,56 @@
+
+ /* high-level funcs, with fallback */
+
+-void
++HB_EXTERN void
++hb_font_get_extents_for_direction (hb_font_t *font,
++ hb_direction_t direction,
++ hb_font_extents_t *extents);
++HB_EXTERN void
+ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+-void
++HB_EXTERN void
+ hb_font_get_glyph_origin_for_direction (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+-void
++HB_EXTERN void
+ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+-void
++HB_EXTERN void
+ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+
+-void
++HB_EXTERN void
+ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
+ hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_glyph_extents_t *extents);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
+ hb_codepoint_t glyph, unsigned int point_index,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y);
+
+ /* Generates gidDDD if glyph has no name. */
+-void
++HB_EXTERN void
+ hb_font_glyph_to_string (hb_font_t *font,
+ hb_codepoint_t glyph,
+ char *s, unsigned int size);
+ /* Parses gidDDD and uniUUUU strings automatically. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_glyph_from_string (hb_font_t *font,
+ const char *s, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph);
+@@ -425,22 +492,22 @@
+
+ /* Fonts are very light-weight objects */
+
+-hb_font_t *
++HB_EXTERN hb_font_t *
+ hb_font_create (hb_face_t *face);
+
+-hb_font_t *
++HB_EXTERN hb_font_t *
+ hb_font_create_sub_font (hb_font_t *parent);
+
+-hb_font_t *
++HB_EXTERN hb_font_t *
+ hb_font_get_empty (void);
+
+-hb_font_t *
++HB_EXTERN hb_font_t *
+ hb_font_reference (hb_font_t *font);
+
+-void
++HB_EXTERN void
+ hb_font_destroy (hb_font_t *font);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_set_user_data (hb_font_t *font,
+ hb_user_data_key_t *key,
+ void * data,
+@@ -448,42 +515,46 @@
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_font_get_user_data (hb_font_t *font,
+ hb_user_data_key_t *key);
+
+-void
++HB_EXTERN void
+ hb_font_make_immutable (hb_font_t *font);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_font_is_immutable (hb_font_t *font);
+
+-hb_font_t *
++HB_EXTERN void
++hb_font_set_parent (hb_font_t *font,
++ hb_font_t *parent);
++
++HB_EXTERN hb_font_t *
+ hb_font_get_parent (hb_font_t *font);
+
+-hb_face_t *
++HB_EXTERN hb_face_t *
+ hb_font_get_face (hb_font_t *font);
+
+
+-void
++HB_EXTERN void
+ hb_font_set_funcs (hb_font_t *font,
+ hb_font_funcs_t *klass,
+ void *font_data,
+ hb_destroy_func_t destroy);
+
+ /* Be *very* careful with this function! */
+-void
++HB_EXTERN void
+ hb_font_set_funcs_data (hb_font_t *font,
+ void *font_data,
+ hb_destroy_func_t destroy);
+
+
+-void
++HB_EXTERN void
+ hb_font_set_scale (hb_font_t *font,
+ int x_scale,
+ int y_scale);
+
+-void
++HB_EXTERN void
+ hb_font_get_scale (hb_font_t *font,
+ int *x_scale,
+ int *y_scale);
+@@ -491,12 +562,12 @@
+ /*
+ * A zero value means "no hinting in that direction"
+ */
+-void
++HB_EXTERN void
+ hb_font_set_ppem (hb_font_t *font,
+ unsigned int x_ppem,
+ unsigned int y_ppem);
+
+-void
++HB_EXTERN void
+ hb_font_get_ppem (hb_font_t *font,
+ unsigned int *x_ppem,
+ unsigned int *y_ppem);
+diff -uN gfx/harfbuzz/src_old/hb-font-private.hh gfx/harfbuzz/src/hb-font-private.hh
+--- gfx/harfbuzz/src_old/hb-font-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-font-private.hh 2016-06-05 23:48:46.442201028 +0200
+@@ -42,6 +42,8 @@
+ */
+
+ #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
++ HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
++ HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
+ HB_FONT_FUNC_IMPLEMENT (glyph) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
+@@ -61,14 +63,6 @@
+
+ hb_bool_t immutable;
+
+- /* Don't access these directly. Call hb_font_get_*() instead. */
+-
+- struct {
+-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+-#undef HB_FONT_FUNC_IMPLEMENT
+- } get;
+-
+ struct {
+ #define HB_FONT_FUNC_IMPLEMENT(name) void *name;
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+@@ -80,6 +74,16 @@
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+ #undef HB_FONT_FUNC_IMPLEMENT
+ } destroy;
++
++ /* 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);
++ } get;
+ };
+
+
+@@ -144,7 +148,36 @@
+
+ /* Public getters */
+
+- inline hb_bool_t has_glyph (hb_codepoint_t unicode)
++ HB_INTERNAL bool has_func (unsigned int i);
++
++ /* has_* ... */
++#define HB_FONT_FUNC_IMPLEMENT(name) \
++ bool \
++ has_##name##_func (void) \
++ { \
++ hb_font_funcs_t *funcs = this->klass; \
++ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
++ return has_func (i); \
++ }
++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
++#undef HB_FONT_FUNC_IMPLEMENT
++
++ inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
++ {
++ memset (extents, 0, sizeof (*extents));
++ return klass->get.f.font_h_extents (this, user_data,
++ extents,
++ klass->user_data.font_h_extents);
++ }
++ inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
++ {
++ memset (extents, 0, sizeof (*extents));
++ return klass->get.f.font_v_extents (this, user_data,
++ extents,
++ klass->user_data.font_v_extents);
++ }
++
++ inline bool has_glyph (hb_codepoint_t unicode)
+ {
+ hb_codepoint_t glyph;
+ return get_glyph (unicode, 0, &glyph);
+@@ -154,85 +187,85 @@
+ hb_codepoint_t *glyph)
+ {
+ *glyph = 0;
+- return klass->get.glyph (this, user_data,
+- unicode, variation_selector, glyph,
+- klass->user_data.glyph);
++ return klass->get.f.glyph (this, user_data,
++ unicode, variation_selector, glyph,
++ klass->user_data.glyph);
+ }
+
+ inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+ {
+- return klass->get.glyph_h_advance (this, user_data,
+- glyph,
+- klass->user_data.glyph_h_advance);
++ return klass->get.f.glyph_h_advance (this, user_data,
++ glyph,
++ klass->user_data.glyph_h_advance);
+ }
+
+ inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+ {
+- return klass->get.glyph_v_advance (this, user_data,
+- glyph,
+- klass->user_data.glyph_v_advance);
++ return klass->get.f.glyph_v_advance (this, user_data,
++ glyph,
++ klass->user_data.glyph_v_advance);
+ }
+
+ inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+- return klass->get.glyph_h_origin (this, user_data,
+- glyph, x, y,
+- klass->user_data.glyph_h_origin);
++ return klass->get.f.glyph_h_origin (this, user_data,
++ glyph, x, y,
++ klass->user_data.glyph_h_origin);
+ }
+
+ inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+- return klass->get.glyph_v_origin (this, user_data,
+- glyph, x, y,
+- klass->user_data.glyph_v_origin);
++ return klass->get.f.glyph_v_origin (this, user_data,
++ glyph, x, y,
++ klass->user_data.glyph_v_origin);
+ }
+
+ inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+ {
+- return klass->get.glyph_h_kerning (this, user_data,
+- left_glyph, right_glyph,
+- klass->user_data.glyph_h_kerning);
++ return klass->get.f.glyph_h_kerning (this, user_data,
++ left_glyph, right_glyph,
++ klass->user_data.glyph_h_kerning);
+ }
+
+ inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
+ {
+- return klass->get.glyph_v_kerning (this, user_data,
+- top_glyph, bottom_glyph,
+- klass->user_data.glyph_v_kerning);
++ return klass->get.f.glyph_v_kerning (this, user_data,
++ top_glyph, bottom_glyph,
++ klass->user_data.glyph_v_kerning);
+ }
+
+ inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents)
+ {
+ memset (extents, 0, sizeof (*extents));
+- return klass->get.glyph_extents (this, user_data,
+- glyph,
+- extents,
+- klass->user_data.glyph_extents);
++ return klass->get.f.glyph_extents (this, user_data,
++ glyph,
++ extents,
++ klass->user_data.glyph_extents);
+ }
+
+ inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+- return klass->get.glyph_contour_point (this, user_data,
+- glyph, point_index,
+- x, y,
+- klass->user_data.glyph_contour_point);
++ return klass->get.f.glyph_contour_point (this, user_data,
++ glyph, point_index,
++ x, y,
++ klass->user_data.glyph_contour_point);
+ }
+
+ inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
+ char *name, unsigned int size)
+ {
+ if (size) *name = '\0';
+- return klass->get.glyph_name (this, user_data,
+- glyph,
+- name, size,
+- klass->user_data.glyph_name);
++ return klass->get.f.glyph_name (this, user_data,
++ glyph,
++ name, size,
++ klass->user_data.glyph_name);
+ }
+
+ inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
+@@ -240,15 +273,35 @@
+ {
+ *glyph = 0;
+ if (len == -1) len = strlen (name);
+- return klass->get.glyph_from_name (this, user_data,
+- name, len,
+- glyph,
+- klass->user_data.glyph_from_name);
++ return klass->get.f.glyph_from_name (this, user_data,
++ name, len,
++ glyph,
++ klass->user_data.glyph_from_name);
+ }
+
+
+ /* A bit higher-level, and with fallback */
+
++ inline void get_extents_for_direction (hb_direction_t direction,
++ hb_font_extents_t *extents)
++ {
++ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
++ if (!get_font_h_extents (extents))
++ {
++ extents->ascender = y_scale * .8;
++ extents->descender = y_scale - extents->ascender;
++ extents->line_gap = 0;
++ }
++ } else {
++ if (!get_font_v_extents (extents))
++ {
++ extents->ascender = x_scale / 2;
++ extents->descender = x_scale - extents->ascender;
++ extents->line_gap = 0;
++ }
++ }
++ }
++
+ inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+@@ -268,7 +321,7 @@
+ {
+ *x = get_glyph_h_advance (glyph) / 2;
+
+- /* TODO use font_metics.ascent */
++ /* TODO use font_extents.ascender */
+ *y = y_scale;
+ }
+
+@@ -298,6 +351,26 @@
+ }
+ }
+
++ inline void add_glyph_h_origin (hb_codepoint_t glyph,
++ hb_position_t *x, hb_position_t *y)
++ {
++ hb_position_t origin_x, origin_y;
++
++ get_glyph_h_origin (glyph, &origin_x, &origin_y);
++
++ *x += origin_x;
++ *y += origin_y;
++ }
++ inline void add_glyph_v_origin (hb_codepoint_t glyph,
++ hb_position_t *x, hb_position_t *y)
++ {
++ hb_position_t origin_x, origin_y;
++
++ get_glyph_v_origin (glyph, &origin_x, &origin_y);
++
++ *x += origin_x;
++ *y += origin_y;
++ }
+ inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+@@ -310,6 +383,26 @@
+ *y += origin_y;
+ }
+
++ inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
++ hb_position_t *x, hb_position_t *y)
++ {
++ hb_position_t origin_x, origin_y;
++
++ get_glyph_h_origin (glyph, &origin_x, &origin_y);
++
++ *x -= origin_x;
++ *y -= origin_y;
++ }
++ inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
++ hb_position_t *x, hb_position_t *y)
++ {
++ hb_position_t origin_x, origin_y;
++
++ get_glyph_v_origin (glyph, &origin_x, &origin_y);
++
++ *x -= origin_x;
++ *y -= origin_y;
++ }
+ inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+diff -uN gfx/harfbuzz/src_old/hb-ft.cc gfx/harfbuzz/src/hb-ft.cc
+--- gfx/harfbuzz/src_old/hb-ft.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ft.cc 2016-06-05 23:48:50.916176399 +0200
+@@ -1,6 +1,7 @@
+ /*
+ * Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2009 Keith Stribley
++ * Copyright © 2015 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+@@ -23,6 +24,7 @@
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
++ * Google Author(s): Behdad Esfahbod
+ */
+
+ #include "hb-private.hh"
+@@ -46,10 +48,15 @@
+ * In general, this file does a fine job of what it's supposed to do.
+ * There are, however, things that need more work:
+ *
+- * - We don't handle any load_flags. That definitely has API implications. :(
+- * I believe hb_ft_font_create() should take load_flags input.
+- * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
+- * buggy.
++ * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
++ * Have not investigated.
++ *
++ * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
++ * would work fine. However, we also abuse this API for performing in font-space,
++ * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
++ * for that, such that no rounding etc happens. As such, we don't set ppem, and
++ * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
++ * ourselves, like we do in uniscribe, etc.
+ *
+ * - We don't handle / allow for emboldening / obliqueing.
+ *
+@@ -59,6 +66,94 @@
+ */
+
+
++struct hb_ft_font_t
++{
++ FT_Face ft_face;
++ int load_flags;
++ bool unref; /* Whether to destroy ft_face when done. */
++};
++
++static hb_ft_font_t *
++_hb_ft_font_create (FT_Face ft_face, bool unref)
++{
++ hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
++
++ if (unlikely (!ft_font))
++ return NULL;
++
++ ft_font->ft_face = ft_face;
++ ft_font->unref = unref;
++
++ ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
++
++ return ft_font;
++}
++
++static void
++_hb_ft_font_destroy (hb_ft_font_t *ft_font)
++{
++ if (ft_font->unref)
++ FT_Done_Face (ft_font->ft_face);
++
++ 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_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_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_destroy_func_t) _hb_ft_font_destroy)
++ return NULL;
++
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
++
++ return ft_font->ft_face;
++}
++
++
++
+ static hb_bool_t
+ hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
+ void *font_data,
+@@ -68,17 +163,19 @@
+ void *user_data HB_UNUSED)
+
+ {
+- FT_Face ft_face = (FT_Face) font_data;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
++ unsigned int g;
+
+-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
+- if (unlikely (variation_selector)) {
+- *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
+- return *glyph != 0;
+- }
+-#endif
++ if (likely (!variation_selector))
++ g = FT_Get_Char_Index (ft_font->ft_face, unicode);
++ else
++ g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
+
+- *glyph = FT_Get_Char_Index (ft_face, unicode);
+- return *glyph != 0;
++ if (unlikely (!g))
++ return false;
++
++ *glyph = g;
++ return true;
+ }
+
+ static hb_position_t
+@@ -87,13 +184,15 @@
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
+- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ FT_Fixed v;
+
+- if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
++ if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
+ return 0;
+
++ if (font->x_scale < 0)
++ v = -v;
++
+ return (v + (1<<9)) >> 10;
+ }
+
+@@ -103,31 +202,21 @@
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
+- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ FT_Fixed v;
+
+- if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
++ if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
+ return 0;
+
++ if (font->y_scale < 0)
++ 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_h_origin (hb_font_t *font HB_UNUSED,
+- void *font_data HB_UNUSED,
+- hb_codepoint_t glyph HB_UNUSED,
+- hb_position_t *x HB_UNUSED,
+- hb_position_t *y HB_UNUSED,
+- void *user_data HB_UNUSED)
+-{
+- /* We always work in the horizontal coordinates. */
+- return true;
+-}
+-
+-static hb_bool_t
+ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+@@ -135,10 +224,10 @@
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
+- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
++ FT_Face ft_face = ft_font->ft_face;
+
+- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+ return false;
+
+ /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+@@ -146,6 +235,11 @@
+ *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX;
+ *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
+
++ if (font->x_scale < 0)
++ *x = -*x;
++ if (font->y_scale < 0)
++ *y = -*y;
++
+ return true;
+ }
+
+@@ -156,27 +250,16 @@
+ hb_codepoint_t right_glyph,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ FT_Vector kerningv;
+
+ FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+- if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv))
++ if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
+ return 0;
+
+ return kerningv.x;
+ }
+
+-static hb_position_t
+-hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+- void *font_data HB_UNUSED,
+- hb_codepoint_t top_glyph HB_UNUSED,
+- hb_codepoint_t bottom_glyph HB_UNUSED,
+- void *user_data HB_UNUSED)
+-{
+- /* FreeType API doesn't support vertical kerning */
+- return 0;
+-}
+-
+ static hb_bool_t
+ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
+ void *font_data,
+@@ -184,16 +267,26 @@
+ hb_glyph_extents_t *extents,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
+- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
++ FT_Face ft_face = ft_font->ft_face;
+
+- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+ return false;
+
+ extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
+ extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
+ extents->width = ft_face->glyph->metrics.width;
+ extents->height = -ft_face->glyph->metrics.height;
++ if (font->x_scale < 0)
++ {
++ extents->x_bearing = -extents->x_bearing;
++ extents->width = -extents->width;
++ }
++ if (font->y_scale < 0)
++ {
++ extents->y_bearing = -extents->y_bearing;
++ extents->height = -extents->height;
++ }
+ return true;
+ }
+
+@@ -206,10 +299,10 @@
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
+- int load_flags = FT_LOAD_DEFAULT;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
++ FT_Face ft_face = ft_font->ft_face;
+
+- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
+ return false;
+
+ if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
+@@ -231,9 +324,9 @@
+ char *name, unsigned int size,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+
+- hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
++ hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
+ if (ret && (size && !*name))
+ ret = false;
+
+@@ -247,7 +340,8 @@
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+ {
+- FT_Face ft_face = (FT_Face) font_data;
++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
++ FT_Face ft_face = ft_font->ft_face;
+
+ if (len < 0)
+ *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
+@@ -272,23 +366,76 @@
+ return *glyph != 0;
+ }
+
++static hb_bool_t
++hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
++ void *font_data,
++ hb_font_extents_t *metrics,
++ 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;
++ metrics->ascender = ft_face->size->metrics.ascender;
++ metrics->descender = ft_face->size->metrics.descender;
++ metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
++ if (font->y_scale < 0)
++ {
++ metrics->ascender = -metrics->ascender;
++ metrics->descender = -metrics->descender;
++ metrics->line_gap = -metrics->line_gap;
++ }
++ return true;
++}
++
++static hb_font_funcs_t *static_ft_funcs = NULL;
++
++#ifdef HB_USE_ATEXIT
++static
++void free_static_ft_funcs (void)
++{
++ hb_font_funcs_destroy (static_ft_funcs);
++}
++#endif
+
+-static hb_font_funcs_t *
+-_hb_ft_get_font_funcs (void)
++static void
++_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+ {
+- static const hb_font_funcs_t ft_ffuncs = {
+- HB_OBJECT_HEADER_STATIC,
++retry:
++ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
++
++ if (unlikely (!funcs))
++ {
++ funcs = hb_font_funcs_create ();
++
++ hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
++ //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
++ hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
++ hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
++ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
++ //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
++ hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
++ hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
++ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
++ hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
++ hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
++ hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
++ hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
+
+- true, /* immutable */
++ hb_font_funcs_make_immutable (funcs);
+
+- {
+-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
+- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+-#undef HB_FONT_FUNC_IMPLEMENT
++ if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
++ hb_font_funcs_destroy (funcs);
++ goto retry;
+ }
++
++#ifdef HB_USE_ATEXIT
++ atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
++#endif
+ };
+
+- return const_cast<hb_font_funcs_t *> (&ft_ffuncs);
++ hb_font_set_funcs (font,
++ funcs,
++ _hb_ft_font_create (ft_face, unref),
++ (hb_destroy_func_t) _hb_ft_font_destroy);
+ }
+
+
+@@ -327,7 +474,7 @@
+ *
+ *
+ * Return value: (transfer full):
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_ft_face_create (FT_Face ft_face,
+@@ -340,11 +487,7 @@
+
+ blob = hb_blob_create ((const char *) ft_face->stream->base,
+ (unsigned int) ft_face->stream->size,
+- /* TODO: We assume that it's mmap()'ed, but FreeType code
+- * suggests that there are cases we reach here but font is
+- * not mmapped. For example, when mmap() fails. No idea
+- * how to deal with it better here. */
+- HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
++ HB_MEMORY_MODE_READONLY,
+ ft_face, destroy);
+ face = hb_face_create (blob, ft_face->face_index);
+ hb_blob_destroy (blob);
+@@ -358,6 +501,22 @@
+ return face;
+ }
+
++/**
++ * hb_ft_face_create_referenced:
++ * @ft_face:
++ *
++ *
++ *
++ * 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_destroy_func_t) FT_Done_Face);
++}
++
+ static void
+ hb_ft_face_finalize (FT_Face ft_face)
+ {
+@@ -371,7 +530,7 @@
+ *
+ *
+ * Return value: (transfer full):
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_face_t *
+ hb_ft_face_create_cached (FT_Face ft_face)
+@@ -388,11 +547,6 @@
+ return hb_face_reference ((hb_face_t *) ft_face->generic.data);
+ }
+
+-static void
+-_do_nothing (void)
+-{
+-}
+-
+
+ /**
+ * hb_ft_font_create:
+@@ -402,7 +556,7 @@
+ *
+ *
+ * Return value: (transfer full):
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_font_t *
+ hb_ft_font_create (FT_Face ft_face,
+@@ -414,29 +568,47 @@
+ face = hb_ft_face_create (ft_face, destroy);
+ font = hb_font_create (face);
+ hb_face_destroy (face);
+- hb_font_set_funcs (font,
+- _hb_ft_get_font_funcs (),
+- ft_face, (hb_destroy_func_t) _do_nothing);
++ _hb_ft_font_set_funcs (font, ft_face, false);
+ hb_font_set_scale (font,
+ (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
+ (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
++#if 0 /* hb-ft works in no-hinting model */
+ hb_font_set_ppem (font,
+ ft_face->size->metrics.x_ppem,
+ ft_face->size->metrics.y_ppem);
++#endif
+
+ return font;
+ }
+
++/**
++ * hb_ft_font_create_referenced:
++ * @ft_face:
++ *
++ *
++ *
++ * 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_destroy_func_t) FT_Done_Face);
++}
++
+
+ /* Thread-safe, lock-free, FT_Library */
+
+ static FT_Library ft_library;
+
+-static inline
++#ifdef HB_USE_ATEXIT
++static
+ void free_ft_library (void)
+ {
+ FT_Done_FreeType (ft_library);
+ }
++#endif
+
+ static FT_Library
+ get_ft_library (void)
+@@ -493,30 +665,23 @@
+
+ FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
+
+- assert (font->y_scale >= 0);
+ FT_Set_Char_Size (ft_face,
+- font->x_scale, font->y_scale,
++ abs (font->x_scale), abs (font->y_scale),
+ 0, 0);
+ #if 0
+ font->x_ppem * 72 * 64 / font->x_scale,
+ font->y_ppem * 72 * 64 / font->y_scale);
+ #endif
++ if (font->x_scale < 0 || font->y_scale < 0)
++ {
++ FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
++ 0, font->y_scale < 0 ? -1 : +1};
++ FT_Set_Transform (ft_face, &matrix, NULL);
++ }
+
+ ft_face->generic.data = blob;
+ ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
+
+- hb_font_set_funcs (font,
+- _hb_ft_get_font_funcs (),
+- ft_face,
+- (hb_destroy_func_t) FT_Done_Face);
+-}
+-
+-FT_Face
+-hb_ft_font_get_face (hb_font_t *font)
+-{
+- if (font->destroy == (hb_destroy_func_t) FT_Done_Face ||
+- font->destroy == (hb_destroy_func_t) _do_nothing)
+- return (FT_Face) font->user_data;
+-
+- return NULL;
++ _hb_ft_font_set_funcs (font, ft_face, true);
++ hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
+ }
+diff -uN gfx/harfbuzz/src_old/hb-ft.h gfx/harfbuzz/src/hb-ft.h
+--- gfx/harfbuzz/src_old/hb-ft.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ft.h 2016-06-05 23:48:52.044170188 +0200
+@@ -1,5 +1,6 @@
+ /*
+ * Copyright © 2009 Red Hat, Inc.
++ * Copyright © 2015 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+@@ -22,6 +23,7 @@
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
++ * Google Author(s): Behdad Esfahbod
+ */
+
+ #ifndef HB_FT_H
+@@ -34,28 +36,90 @@
+
+ HB_BEGIN_DECLS
+
+-/* Note: FreeType is not thread-safe. Hence, these functions are not either. */
++/*
++ * Note: FreeType is not thread-safe.
++ * Hence, these functions are not either.
++ */
+
+-hb_face_t *
++/*
++ * hb-face from ft-face.
++ */
++
++/* This one creates a new hb-face for given ft-face.
++ * When the returned hb-face is destroyed, the destroy
++ * callback is called (if not NULL), with the ft-face passed
++ * to it.
++ *
++ * The client is responsible to make sure that ft-face is
++ * destroyed after hb-face is destroyed.
++ *
++ * Most often you don't want this function. You should use either
++ * hb_ft_face_create_cached(), or hb_ft_face_create_referenced().
++ * In particular, if you are going to pass NULL as destroy, you
++ * probably should use (the more recent) hb_ft_face_create_referenced()
++ * instead.
++ */
++HB_EXTERN hb_face_t *
+ hb_ft_face_create (FT_Face ft_face,
+ hb_destroy_func_t destroy);
+
+-hb_face_t *
++/* This version is like hb_ft_face_create(), except that it caches
++ * the hb-face using the generic pointer of the ft-face. This means
++ * that subsequent calls to this function with the same ft-face will
++ * return the same hb-face (correctly referenced).
++ *
++ * Client is still responsible for making sure that ft-face is destroyed
++ * after hb-face is.
++ */
++HB_EXTERN hb_face_t *
+ hb_ft_face_create_cached (FT_Face ft_face);
+
+-hb_font_t *
++/* This version is like hb_ft_face_create(), except that it calls
++ * FT_Reference_Face() on ft-face, as such keeping ft-face alive
++ * as long as the hb-face is.
++ *
++ * This is the most convenient version to use. Use it unless you have
++ * very good reasons not to.
++ */
++HB_EXTERN hb_face_t *
++hb_ft_face_create_referenced (FT_Face ft_face);
++
++
++/*
++ * hb-font from ft-face.
++ */
++
++/*
++ * Note:
++ *
++ * Set face size on ft-face before creating hb-font from it.
++ * Otherwise hb-ft would NOT pick up the font size correctly.
++ */
++
++/* See notes on hb_ft_face_create(). Same issues re lifecycle-management
++ * apply here. Use hb_ft_font_create_referenced() if you can. */
++HB_EXTERN hb_font_t *
+ hb_ft_font_create (FT_Face ft_face,
+ hb_destroy_func_t destroy);
+
++/* See notes on hb_ft_face_create_referenced() re lifecycle-management
++ * issues. */
++HB_EXTERN hb_font_t *
++hb_ft_font_create_referenced (FT_Face ft_face);
++
++HB_EXTERN FT_Face
++hb_ft_font_get_face (hb_font_t *font);
++
++HB_EXTERN void
++hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
+
++HB_EXTERN int
++hb_ft_font_get_load_flags (hb_font_t *font);
+
+ /* Makes an hb_font_t use FreeType internally to implement font functions. */
+-void
++HB_EXTERN void
+ hb_ft_font_set_funcs (hb_font_t *font);
+
+-FT_Face
+-hb_ft_font_get_face (hb_font_t *font);
+-
+
+ HB_END_DECLS
+
+diff -uN gfx/harfbuzz/src_old/hb-glib.cc gfx/harfbuzz/src/hb-glib.cc
+--- gfx/harfbuzz/src_old/hb-glib.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-glib.cc 2016-06-05 23:48:53.244163610 +0200
+@@ -382,3 +382,19 @@
+ return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
+ }
+
++/**
++ * hb_glib_blob_create:
++ *
++ * Since: 0.9.38
++ **/
++hb_blob_t *
++hb_glib_blob_create (GBytes *gbytes)
++{
++ gsize size = 0;
++ gconstpointer data = g_bytes_get_data (gbytes, &size);
++ return hb_blob_create ((const char *) data,
++ size,
++ HB_MEMORY_MODE_READONLY,
++ g_bytes_ref (gbytes),
++ (hb_destroy_func_t) g_bytes_unref);
++}
+diff -uN gfx/harfbuzz/src_old/hb-glib.h gfx/harfbuzz/src/hb-glib.h
+--- gfx/harfbuzz/src_old/hb-glib.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-glib.h 2016-06-05 23:48:54.401157255 +0200
+@@ -36,16 +36,19 @@
+ HB_BEGIN_DECLS
+
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_glib_script_to_script (GUnicodeScript script);
+
+-GUnicodeScript
++HB_EXTERN GUnicodeScript
+ hb_glib_script_from_script (hb_script_t script);
+
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_glib_get_unicode_funcs (void);
+
++HB_EXTERN hb_blob_t *
++hb_glib_blob_create (GBytes *gbytes);
++
+
+ HB_END_DECLS
+
+diff -uN gfx/harfbuzz/src_old/hb-gobject-enums.h.tmpl gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
+--- gfx/harfbuzz/src_old/hb-gobject-enums.h.tmpl 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-gobject-enums.h.tmpl 2016-06-05 23:48:57.189141987 +0200
+@@ -42,7 +42,7 @@
+ /*** END file-header ***/
+
+ /*** BEGIN value-header ***/
+-GType @enum_name@_get_type (void) G_GNUC_CONST;
++HB_EXTERN GType @enum_name@_get_type (void) G_GNUC_CONST;
+ #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+
+ /*** END value-header ***/
+diff -uN gfx/harfbuzz/src_old/hb-gobject-structs.cc gfx/harfbuzz/src/hb-gobject-structs.cc
+--- gfx/harfbuzz/src_old/hb-gobject-structs.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-gobject-structs.cc 2016-06-05 23:48:58.408135321 +0200
+@@ -54,6 +54,17 @@
+ #define HB_DEFINE_OBJECT_TYPE(name) \
+ HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
+
++#define HB_DEFINE_VALUE_TYPE(name) \
++ static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
++ { \
++ hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
++ if (unlikely (!c)) return NULL; \
++ *c = *l; \
++ return c; \
++ } \
++ static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
++ HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy);
++
+ HB_DEFINE_OBJECT_TYPE (buffer)
+ HB_DEFINE_OBJECT_TYPE (blob)
+ HB_DEFINE_OBJECT_TYPE (face)
+@@ -62,59 +73,8 @@
+ HB_DEFINE_OBJECT_TYPE (set)
+ HB_DEFINE_OBJECT_TYPE (shape_plan)
+ HB_DEFINE_OBJECT_TYPE (unicode_funcs)
+-
+-
+-static hb_feature_t *feature_reference (hb_feature_t *g)
+-{
+- hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t));
+- if (unlikely (!c)) return NULL;
+- *c = *g;
+- return c;
+-}
+-static void feature_destroy (hb_feature_t *g) { free (g); }
+-HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy)
+-
+-static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g)
+-{
+- hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t));
+- if (unlikely (!c)) return NULL;
+- *c = *g;
+- return c;
+-}
+-static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); }
+-HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy)
+-
+-static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g)
+-{
+- hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t));
+- if (unlikely (!c)) return NULL;
+- *c = *g;
+- return c;
+-}
+-static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); }
+-HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy)
+-
+-static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g)
+-{
+- hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t));
+- if (unlikely (!c)) return NULL;
+- *c = *g;
+- return c;
+-}
+-static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); }
+-HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy)
+-
+-static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; }
+-static void user_data_key_destroy (hb_user_data_key_t l) { }
+-HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy)
+-
+-
+-static hb_language_t *language_reference (hb_language_t *l)
+-{
+- hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t));
+- if (unlikely (!c)) return NULL;
+- *c = *l;
+- return c;
+-}
+-static void language_destroy (hb_language_t *l) { free (l); }
+-HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy)
++HB_DEFINE_VALUE_TYPE (feature)
++HB_DEFINE_VALUE_TYPE (glyph_info)
++HB_DEFINE_VALUE_TYPE (glyph_position)
++HB_DEFINE_VALUE_TYPE (segment_properties)
++HB_DEFINE_VALUE_TYPE (user_data_key)
+diff -uN gfx/harfbuzz/src_old/hb-gobject-structs.h gfx/harfbuzz/src/hb-gobject-structs.h
+--- gfx/harfbuzz/src_old/hb-gobject-structs.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-gobject-structs.h 2016-06-05 23:48:59.577128929 +0200
+@@ -40,55 +40,65 @@
+
+ /* Object types */
+
+-GType hb_gobject_blob_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_blob_get_type (void);
+ #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
+
+-GType hb_gobject_buffer_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_buffer_get_type (void);
+ #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
+
+-GType hb_gobject_face_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_face_get_type (void);
+ #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
+
+-GType hb_gobject_font_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_font_get_type (void);
+ #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
+
+-GType hb_gobject_font_funcs_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_font_funcs_get_type (void);
+ #define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
+
+-GType hb_gobject_set_get_type (void);
++HB_EXTERN GType hb_gobject_set_get_type (void);
+ #define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
+
+-GType hb_gobject_shape_plan_get_type (void);
++HB_EXTERN GType hb_gobject_shape_plan_get_type (void);
+ #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
+
+-GType hb_gobject_unicode_funcs_get_type (void);
++/**
++ * Since: 0.9.2
++ **/
++HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void);
+ #define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
+
+ /* Value types */
+
+-GType hb_gobject_feature_get_type (void);
++HB_EXTERN GType hb_gobject_feature_get_type (void);
+ #define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
+
+-GType hb_gobject_glyph_info_get_type (void);
++HB_EXTERN GType hb_gobject_glyph_info_get_type (void);
+ #define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
+
+-GType hb_gobject_glyph_position_get_type (void);
++HB_EXTERN GType hb_gobject_glyph_position_get_type (void);
+ #define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
+
+-GType hb_gobject_segment_properties_get_type (void);
++HB_EXTERN GType hb_gobject_segment_properties_get_type (void);
+ #define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
+
+-GType hb_gobject_user_data_key_get_type (void);
++HB_EXTERN GType hb_gobject_user_data_key_get_type (void);
+ #define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
+
+-/* Currently gobject-introspection doesn't understand that hb_language_t
+- * can be passed by-value. As such we box it up. May remove in the
+- * future.
+- *
+- * https://bugzilla.gnome.org/show_bug.cgi?id=707656
+- */
+-GType hb_gobject_language_get_type (void);
+-#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ())
+
+ HB_END_DECLS
+
+diff -uN gfx/harfbuzz/src_old/hb-graphite2.cc gfx/harfbuzz/src/hb-graphite2.cc
+--- gfx/harfbuzz/src_old/hb-graphite2.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-graphite2.cc 2016-06-05 23:49:01.899116257 +0200
+@@ -138,6 +138,9 @@
+ free (data);
+ }
+
++/*
++ * Since: 0.9.10
++ */
+ gr_face *
+ hb_graphite2_face_get_gr_face (hb_face_t *face)
+ {
+@@ -172,6 +175,9 @@
+ gr_font_destroy (data);
+ }
+
++/*
++ * Since: 0.9.10
++ */
+ gr_font *
+ hb_graphite2_font_get_gr_font (hb_font_t *font)
+ {
+@@ -228,12 +234,11 @@
+ int lang_len = lang_end ? lang_end - lang : -1;
+ gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
+
+- while (num_features--)
++ for (unsigned int i = 0; i < num_features; i++)
+ {
+- const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
++ const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
+ if (fref)
+- gr_fref_set_feature_value (fref, features->value, feats);
+- features++;
++ gr_fref_set_feature_value (fref, features[i].value, feats);
+ }
+
+ gr_segment *seg = NULL;
+@@ -249,6 +254,8 @@
+ for (unsigned int i = 0; i < buffer->len; ++i)
+ chars[i] = buffer->info[i].codepoint;
+
++ /* TODO ensure_native_direction. */
++
+ hb_tag_t script_tag[2];
+ hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
+
+@@ -267,9 +274,11 @@
+ if (unlikely (!glyph_count)) {
+ if (feats) gr_featureval_destroy (feats);
+ gr_seg_destroy (seg);
+- return false;
++ buffer->len = 0;
++ return true;
+ }
+
++ buffer->ensure (glyph_count);
+ scratch = buffer->get_scratch_buffer (&scratch_size);
+ while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
+ DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
+@@ -331,7 +340,6 @@
+ }
+ ci++;
+
+- //buffer->clear_output ();
+ for (unsigned int i = 0; i < ci; ++i)
+ {
+ for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
+@@ -342,32 +350,58 @@
+ }
+ }
+ buffer->len = glyph_count;
+- //buffer->swap_buffers ();
+-
+- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+- curradvx = gr_seg_advance_X(seg);
+
+- hb_glyph_position_t *pPos;
+- for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
+- is; pPos++, is = gr_slot_next_in_segment (is))
+- {
+- pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+- pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
+- pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+- pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
+- if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+- curradvx -= pPos->x_advance;
+- pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+- if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
++ float yscale = font->y_scale / font->x_scale;
++ /* Positioning. */
++ if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
++ {
++ hb_glyph_position_t *pPos;
++ for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
++ is; pPos++, is = gr_slot_next_in_segment (is))
++ {
++ pPos->x_offset = gr_slot_origin_X (is) - curradvx;
++ pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
++ pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
++ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
+ curradvx += pPos->x_advance;
+- pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
+- curradvy += pPos->y_advance;
+- }
+- if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
++ curradvy += pPos->y_advance;
++ }
+ pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+-
+- if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
++ }
++ else
++ {
++ hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL) + buffer->len - 1;
++ const hb_glyph_info_t *info = buffer->info + buffer->len - 1;
++ const hb_glyph_info_t *tinfo;
++ const gr_slot *tis;
++ int currclus = -1;
++ float clusx = 0., clusy = 0.;
++ for (is = gr_seg_last_slot (seg); is; pPos--, info--, is = gr_slot_prev_in_segment (is))
++ {
++ if (info->cluster != currclus)
++ {
++ curradvx += clusx;
++ curradvy += clusy;
++ currclus = info->cluster;
++ clusx = 0.;
++ clusy = 0.;
++ for (tis = is, tinfo = info; tis && tinfo->cluster == currclus; tis = gr_slot_prev_in_segment (tis), tinfo--)
++ {
++ clusx += gr_slot_advance_X (tis, grface, grfont);
++ clusy += gr_slot_advance_Y (tis, grface, grfont) * yscale;
++ }
++ curradvx += clusx;
++ curradvy += clusy;
++ }
++ pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
++ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
++ curradvx -= pPos->x_advance;
++ curradvy -= pPos->y_advance;
++ pPos->x_offset = gr_slot_origin_X (is) - curradvx;
++ pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
++ }
+ hb_buffer_reverse_clusters (buffer);
++ }
+
+ if (feats) gr_featureval_destroy (feats);
+ gr_seg_destroy (seg);
+diff -uN gfx/harfbuzz/src_old/hb-graphite2.h gfx/harfbuzz/src/hb-graphite2.h
+--- gfx/harfbuzz/src_old/hb-graphite2.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-graphite2.h 2016-06-05 23:49:03.057109946 +0200
+@@ -36,10 +36,10 @@
+ #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
+
+
+-gr_face *
++HB_EXTERN gr_face *
+ hb_graphite2_face_get_gr_face (hb_face_t *face);
+
+-gr_font *
++HB_EXTERN gr_font *
+ hb_graphite2_font_get_gr_font (hb_font_t *font);
+
+
+diff -uN gfx/harfbuzz/src_old/hb.h gfx/harfbuzz/src/hb.h
+--- gfx/harfbuzz/src_old/hb.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb.h 2016-06-05 23:50:56.057516793 +0200
+@@ -28,6 +28,10 @@
+ #define HB_H
+ #define HB_H_IN
+
++#ifndef HB_EXTERN
++#define HB_EXTERN extern
++#endif
++
+ #include "hb-blob.h"
+ #include "hb-buffer.h"
+ #include "hb-common.h"
+diff -uN gfx/harfbuzz/src_old/hb-icu.cc gfx/harfbuzz/src/hb-icu.cc
+--- gfx/harfbuzz/src_old/hb-icu.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-icu.cc 2016-06-05 23:49:04.387102711 +0200
+@@ -363,10 +363,8 @@
+ if (!hb_atomic_ptr_get (&normalizer)) {
+ UErrorCode icu_err = U_ZERO_ERROR;
+ /* We ignore failure in getNFCInstace(). */
+- hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
++ (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
+ }
+ #endif
+ return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
+ }
+-
+-
+diff -uN gfx/harfbuzz/src_old/hb-icu.h gfx/harfbuzz/src/hb-icu.h
+--- gfx/harfbuzz/src_old/hb-icu.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-icu.h 2016-06-05 23:49:05.565096299 +0200
+@@ -36,14 +36,14 @@
+ HB_BEGIN_DECLS
+
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_icu_script_to_script (UScriptCode script);
+
+-UScriptCode
++HB_EXTERN UScriptCode
+ hb_icu_script_from_script (hb_script_t script);
+
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_icu_get_unicode_funcs (void);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-mutex-private.hh gfx/harfbuzz/src/hb-mutex-private.hh
+--- gfx/harfbuzz/src_old/hb-mutex-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-mutex-private.hh 2016-06-05 23:49:06.735089929 +0200
+@@ -39,7 +39,13 @@
+
+ /* We need external help for these */
+
+-#if 0
++#if defined(HB_MUTEX_IMPL_INIT) \
++ && defined(hb_mutex_impl_init) \
++ && defined(hb_mutex_impl_lock) \
++ && defined(hb_mutex_impl_unlock) \
++ && defined(hb_mutex_impl_finish)
++
++/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
+
+
+ #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
+@@ -47,7 +53,11 @@
+ #include <windows.h>
+ typedef CRITICAL_SECTION hb_mutex_impl_t;
+ #define HB_MUTEX_IMPL_INIT {0}
++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
++#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
++#else
+ #define hb_mutex_impl_init(M) InitializeCriticalSection (M)
++#endif
+ #define hb_mutex_impl_lock(M) EnterCriticalSection (M)
+ #define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
+ #define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
+@@ -109,10 +119,12 @@
+ #define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
+ #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
+
++
+ #endif
+
+
+ #define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT}
++
+ struct hb_mutex_t
+ {
+ /* TODO Add tracing. */
+diff -uN gfx/harfbuzz/src_old/hb-object-private.hh gfx/harfbuzz/src/hb-object-private.hh
+--- gfx/harfbuzz/src_old/hb-object-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-object-private.hh 2016-06-05 23:49:07.940083385 +0200
+@@ -47,19 +47,22 @@
+
+ /* reference_count */
+
+-#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1)
+-#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE}
++#define HB_REFERENCE_COUNT_INERT_VALUE -1
++#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
++#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)}
++
+ struct hb_reference_count_t
+ {
+ hb_atomic_int_t ref_count;
+
+- inline void init (int v) { ref_count = v; }
+- inline int inc (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count), 1); }
+- inline int dec (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count), -1); }
+- inline void finish (void) { ref_count = HB_REFERENCE_COUNT_INVALID_VALUE; }
+-
+- inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; }
++ inline void init (int v) { ref_count.set_unsafe (v); }
++ inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
++ inline int inc (void) { return ref_count.inc (); }
++ inline int dec (void) { return ref_count.dec (); }
++ inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
+
++ inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
++ inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
+ };
+
+
+@@ -102,7 +105,7 @@
+ hb_reference_count_t ref_count;
+ hb_user_data_array_t user_data;
+
+-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
++#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT}
+
+ private:
+ ASSERT_POD ();
+@@ -117,7 +120,7 @@
+ DEBUG_MSG (OBJECT, (void *) obj,
+ "%s refcount=%d",
+ function,
+- obj ? obj->header.ref_count.ref_count : 0);
++ obj ? obj->header.ref_count.get_unsafe () : 0);
+ }
+
+ template <typename Type>
+@@ -141,7 +144,12 @@
+ template <typename Type>
+ static inline bool hb_object_is_inert (const Type *obj)
+ {
+- return unlikely (obj->header.ref_count.is_invalid ());
++ return unlikely (obj->header.ref_count.is_inert ());
++}
++template <typename Type>
++static inline bool hb_object_is_valid (const Type *obj)
++{
++ return likely (obj->header.ref_count.is_valid ());
+ }
+ template <typename Type>
+ static inline Type *hb_object_reference (Type *obj)
+@@ -149,6 +157,7 @@
+ hb_object_trace (obj, HB_FUNC);
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return obj;
++ assert (hb_object_is_valid (obj));
+ obj->header.ref_count.inc ();
+ return obj;
+ }
+@@ -158,6 +167,7 @@
+ hb_object_trace (obj, HB_FUNC);
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return false;
++ assert (hb_object_is_valid (obj));
+ if (obj->header.ref_count.dec () != 1)
+ return false;
+
+@@ -174,6 +184,7 @@
+ {
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return false;
++ assert (hb_object_is_valid (obj));
+ return obj->header.user_data.set (key, data, destroy, replace);
+ }
+
+@@ -183,6 +194,7 @@
+ {
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return NULL;
++ assert (hb_object_is_valid (obj));
+ return obj->header.user_data.get (key);
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-open-file-private.hh gfx/harfbuzz/src/hb-open-file-private.hh
+--- gfx/harfbuzz/src_old/hb-open-file-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-open-file-private.hh 2016-06-05 23:49:09.207076516 +0200
+@@ -53,9 +53,10 @@
+
+ typedef struct TableRecord
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ Tag tag; /* 4-byte identifier. */
+@@ -102,9 +103,10 @@
+ }
+
+ public:
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
++ return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
+ }
+
+ protected:
+@@ -130,9 +132,10 @@
+ inline unsigned int get_face_count (void) const { return table.len; }
+ inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (table.sanitize (c, this));
++ return_trace (table.sanitize (c, this));
+ }
+
+ protected:
+@@ -169,13 +172,14 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
++ if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
+ switch (u.header.version.major) {
+ case 2: /* version 2 is compatible with version 1 */
+- case 1: return TRACE_RETURN (u.version1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.version1.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -233,16 +237,17 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
++ if (unlikely (!u.tag.sanitize (c))) return_trace (false);
+ switch (u.tag) {
+ case CFFTag: /* All the non-collection tags */
+ case TrueTag:
+ case Typ1Tag:
+- case TrueTypeTag: return TRACE_RETURN (u.fontFace.sanitize (c));
+- case TTCTag: return TRACE_RETURN (u.ttcHeader.sanitize (c));
+- default: return TRACE_RETURN (true);
++ case TrueTypeTag: return_trace (u.fontFace.sanitize (c));
++ case TTCTag: return_trace (u.ttcHeader.sanitize (c));
++ default: return_trace (true);
+ }
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-open-type-private.hh gfx/harfbuzz/src/hb-open-type-private.hh
+--- gfx/harfbuzz/src_old/hb-open-type-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-open-type-private.hh 2016-06-05 23:49:10.574069085 +0200
+@@ -103,9 +103,6 @@
+ static const unsigned int static_size = (size); \
+ static const unsigned int min_size = (size)
+
+-/* Size signifying variable-sized array */
+-#define VAR 1
+-
+ #define DEFINE_SIZE_UNION(size, _member) \
+ DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
+ static const unsigned int min_size = (size)
+@@ -154,6 +151,20 @@
+ #define Null(Type) Null<Type>()
+
+
++/*
++ * Dispatch
++ */
++
++template <typename Context, typename Return, unsigned int MaxDebugDepth>
++struct hb_dispatch_context_t
++{
++ static const unsigned int max_debug_depth = MaxDebugDepth;
++ typedef Return return_t;
++ template <typename T, typename F>
++ inline bool may_dispatch (const T *obj, const F *format) { return true; }
++ static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
++};
++
+
+ /*
+ * Sanitize
+@@ -171,18 +182,27 @@
+
+ /* This limits sanitizing time on really broken fonts. */
+ #ifndef HB_SANITIZE_MAX_EDITS
+-#define HB_SANITIZE_MAX_EDITS 100
++#define HB_SANITIZE_MAX_EDITS 32
+ #endif
+
+-struct hb_sanitize_context_t
++struct hb_sanitize_context_t :
++ hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
+ {
++ inline hb_sanitize_context_t (void) :
++ debug_depth (0),
++ start (NULL), end (NULL),
++ writable (false), edit_count (0),
++ blob (NULL) {}
++
+ inline const char *get_name (void) { return "SANITIZE"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
+- typedef bool return_t;
++ template <typename T, typename F>
++ inline bool may_dispatch (const T *obj, const F *format)
++ { return format->sanitize (this); }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
+ static return_t default_return_value (void) { return true; }
+- bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
++ static return_t no_dispatch_return_value (void) { return false; }
++ bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
+ inline void init (hb_blob_t *b)
+ {
+@@ -270,9 +290,9 @@
+ }
+
+ template <typename Type, typename ValueType>
+- inline bool try_set (Type *obj, const ValueType &v) {
++ inline bool try_set (const Type *obj, const ValueType &v) {
+ if (this->may_edit (obj, obj->static_size)) {
+- obj->set (v);
++ const_cast<Type *> (obj)->set (v);
+ return true;
+ }
+ return false;
+@@ -292,7 +312,7 @@
+ struct Sanitizer
+ {
+ static hb_blob_t *sanitize (hb_blob_t *blob) {
+- hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
++ hb_sanitize_context_t c[1];
+ bool sane;
+
+ /* TODO is_sane() stuff */
+@@ -376,9 +396,9 @@
+
+ struct hb_serialize_context_t
+ {
+- inline hb_serialize_context_t (void *start, unsigned int size)
++ inline hb_serialize_context_t (void *start_, unsigned int size)
+ {
+- this->start = (char *) start;
++ this->start = (char *) start_;
+ this->end = this->start + size;
+
+ this->ran_out_of_room = false;
+@@ -472,10 +492,10 @@
+ return reinterpret_cast<Type *> (&obj);
+ }
+
+- inline void truncate (void *head)
++ inline void truncate (void *new_head)
+ {
+- assert (this->start < head && head <= this->head);
+- this->head = (char *) head;
++ assert (this->start < new_head && new_head <= this->head);
++ this->head = (char *) new_head;
+ }
+
+ unsigned int debug_depth;
+@@ -533,6 +553,20 @@
+ template <typename Type, int Bytes> struct BEInt;
+
+ template <typename Type>
++struct BEInt<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 BEInt<Type, 2>
+ {
+ public:
+@@ -546,12 +580,6 @@
+ return (v[0] << 8)
+ + (v[1] );
+ }
+- inline bool operator == (const BEInt<Type, 2>& o) const
+- {
+- return v[0] == o.v[0]
+- && v[1] == o.v[1];
+- }
+- inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
+ private: uint8_t v[2];
+ };
+ template <typename Type>
+@@ -570,13 +598,6 @@
+ + (v[1] << 8)
+ + (v[2] );
+ }
+- inline bool operator == (const BEInt<Type, 3>& o) const
+- {
+- return v[0] == o.v[0]
+- && v[1] == o.v[1]
+- && v[2] == o.v[2];
+- }
+- inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
+ private: uint8_t v[3];
+ };
+ template <typename Type>
+@@ -597,14 +618,6 @@
+ + (v[2] << 8)
+ + (v[3] );
+ }
+- inline bool operator == (const BEInt<Type, 4>& o) const
+- {
+- return v[0] == o.v[0]
+- && v[1] == o.v[1]
+- && v[2] == o.v[2]
+- && v[3] == o.v[3];
+- }
+- inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
+ private: uint8_t v[4];
+ };
+
+@@ -614,14 +627,21 @@
+ {
+ inline void set (Type i) { v.set (i); }
+ inline operator Type(void) const { return v; }
+- inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; }
+- inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; }
++ inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
++ inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+ static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+- inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
+- inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline int cmp (Type a) const
++ {
++ Type b = v;
++ if (sizeof (Type) < sizeof (int))
++ return (int) a - (int) b;
++ else
++ return a < b ? -1 : a == b ? 0 : +1;
++ }
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (likely (c->check_struct (this)));
++ return_trace (likely (c->check_struct (this)));
+ }
+ protected:
+ BEInt<Type, Size> v;
+@@ -629,7 +649,7 @@
+ DEFINE_SIZE_STATIC (Size);
+ };
+
+-typedef uint8_t BYTE; /* 8-bit unsigned integer. */
++typedef IntType<uint8_t , 1> BYTE; /* 8-bit unsigned integer. */
+ typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
+ typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
+ typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
+@@ -646,9 +666,10 @@
+ * 1904. The value is represented as a signed 64-bit integer. */
+ struct LONGDATETIME
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (likely (c->check_struct (this)));
++ return_trace (likely (c->check_struct (this)));
+ }
+ protected:
+ LONG major;
+@@ -670,7 +691,10 @@
+ DEFINE_NULL_DATA (Tag, " ");
+
+ /* Glyph index number, same as uint16 (length = 16 bits) */
+-typedef USHORT GlyphID;
++struct GlyphID : USHORT {
++ static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
++ inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
++};
+
+ /* Script/language-system/feature index */
+ struct Index : USHORT {
+@@ -719,9 +743,10 @@
+ {
+ inline uint32_t to_int (void) const { return (major << 16) + minor; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ USHORT major;
+@@ -747,33 +772,35 @@
+ return StructAtOffset<Type> (base, offset);
+ }
+
+- inline Type& serialize (hb_serialize_context_t *c, void *base)
++ inline Type& serialize (hb_serialize_context_t *c, const void *base)
+ {
+ Type *t = c->start_embed<Type> ();
+ this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+ return *t;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
++ if (unlikely (!c->check_struct (this))) return_trace (false);
+ unsigned int offset = *this;
+- if (unlikely (!offset)) return TRACE_RETURN (true);
+- Type &obj = StructAtOffset<Type> (base, offset);
+- return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
++ if (unlikely (!offset)) return_trace (true);
++ const Type &obj = StructAtOffset<Type> (base, offset);
++ return_trace (likely (obj.sanitize (c)) || neuter (c));
+ }
+ template <typename T>
+- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
++ if (unlikely (!c->check_struct (this))) return_trace (false);
+ unsigned int offset = *this;
+- if (unlikely (!offset)) return TRACE_RETURN (true);
+- Type &obj = StructAtOffset<Type> (base, offset);
+- return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
++ if (unlikely (!offset)) return_trace (true);
++ const Type &obj = StructAtOffset<Type> (base, offset);
++ return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
+ }
+
+ /* Set the offset to Null */
+- inline bool neuter (hb_sanitize_context_t *c) {
++ inline bool neuter (hb_sanitize_context_t *c) const {
+ return c->try_set (this, 0);
+ }
+ DEFINE_SIZE_STATIC (sizeof(OffsetType));
+@@ -820,10 +847,10 @@
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ len.set (items_len); /* TODO(serialize) Overflow? */
+- if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!c->extend (*this))) return_trace (false);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -831,16 +858,17 @@
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
++ if (unlikely (!serialize (c, items_len))) return_trace (false);
+ for (unsigned int i = 0; i < items_len; i++)
+ array[i] = items[i];
+ items.advance (items_len);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
++ 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
+@@ -851,26 +879,28 @@
+ */
+ (void) (false && array[0].sanitize (c));
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
++ if (unlikely (!sanitize_shallow (c))) return_trace (false);
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!array[i].sanitize (c, base)))
+- return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ return_trace (false);
++ return_trace (true);
+ }
+ template <typename T>
+- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
++ if (unlikely (!sanitize_shallow (c))) return_trace (false);
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!array[i].sanitize (c, base, user_data)))
+- return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ return_trace (false);
++ return_trace (true);
+ }
+
+ template <typename SearchType>
+@@ -884,9 +914,10 @@
+ }
+
+ private:
+- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
++ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
++ return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len));
+ }
+
+ public:
+@@ -910,14 +941,16 @@
+ return this+this->array[i];
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
++ return_trace (OffsetArrayOf<Type>::sanitize (c, this));
+ }
+ template <typename T>
+- inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
++ inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
++ return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
+ }
+ };
+
+@@ -939,24 +972,26 @@
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ len.set (items_len); /* TODO(serialize) Overflow? */
+- if (unlikely (!items_len)) return TRACE_RETURN (true);
+- if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
++ if (unlikely (!items_len)) return_trace (true);
++ if (unlikely (!c->extend (*this))) return_trace (false);
+ for (unsigned int i = 0; i < items_len - 1; i++)
+ array[i] = items[i];
+ items.advance (items_len - 1);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
++ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
++ {
+ return c->check_struct (this)
+ && c->check_array (this, Type::static_size, len);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
++ 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
+@@ -967,7 +1002,7 @@
+ */
+ (void) (false && array[0].sanitize (c));
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ LenType len;
+diff -uN gfx/harfbuzz/src_old/hb-ot-cmap-table.hh gfx/harfbuzz/src/hb-ot-cmap-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-cmap-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-cmap-table.hh 2016-06-05 23:49:11.982061464 +0200
+@@ -51,9 +51,10 @@
+ return true;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ protected:
+@@ -125,11 +126,11 @@
+ return true;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c)
++ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_struct (this)))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ if (unlikely (!c->check_range (this, length)))
+ {
+@@ -140,10 +141,10 @@
+ (uintptr_t) (c->end -
+ (char *) this));
+ if (!c->try_set (&length, new_length))
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+- return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
++ return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
+ }
+
+ protected:
+@@ -183,9 +184,10 @@
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ private:
+@@ -210,9 +212,10 @@
+ return true;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
++ return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
+ }
+
+ protected:
+@@ -242,9 +245,10 @@
+ return true;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
++ return_trace (c->check_struct (this) && groups.sanitize (c));
+ }
+
+ protected:
+@@ -288,9 +292,10 @@
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ UINT24 startUnicodeValue; /* First value in this range. */
+@@ -309,9 +314,10 @@
+ return unicodeValue.cmp (codepoint);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ UINT24 unicodeValue; /* Base Unicode value of the UVS */
+@@ -348,11 +354,12 @@
+ return varSelector.cmp (variation_selector);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- defaultUVS.sanitize (c, base) &&
+- nonDefaultUVS.sanitize (c, base));
++ return_trace (c->check_struct (this) &&
++ defaultUVS.sanitize (c, base) &&
++ nonDefaultUVS.sanitize (c, base));
+ }
+
+ UINT24 varSelector; /* Variation selector. */
+@@ -373,10 +380,11 @@
+ return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- record.sanitize (c, this));
++ return_trace (c->check_struct (this) &&
++ record.sanitize (c, this));
+ }
+
+ protected:
+@@ -418,18 +426,19 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 0: return TRACE_RETURN (u.format0 .sanitize (c));
+- case 4: return TRACE_RETURN (u.format4 .sanitize (c));
+- case 6: return TRACE_RETURN (u.format6 .sanitize (c));
+- case 10: return TRACE_RETURN (u.format10.sanitize (c));
+- case 12: return TRACE_RETURN (u.format12.sanitize (c));
+- case 13: return TRACE_RETURN (u.format13.sanitize (c));
+- case 14: return TRACE_RETURN (u.format14.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 0: return_trace (u.format0 .sanitize (c));
++ case 4: return_trace (u.format4 .sanitize (c));
++ case 6: return_trace (u.format6 .sanitize (c));
++ case 10: return_trace (u.format10.sanitize (c));
++ case 12: return_trace (u.format12.sanitize (c));
++ case 13: return_trace (u.format13.sanitize (c));
++ case 14: return_trace (u.format14.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -461,10 +470,11 @@
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- subtable.sanitize (c, base));
++ return_trace (c->check_struct (this) &&
++ subtable.sanitize (c, base));
+ }
+
+ USHORT platformID; /* Platform ID. */
+@@ -496,11 +506,12 @@
+ return &(this+encodingRecord[result].subtable);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- likely (version == 0) &&
+- encodingRecord.sanitize (c, this));
++ return_trace (c->check_struct (this) &&
++ likely (version == 0) &&
++ encodingRecord.sanitize (c, this));
+ }
+
+ USHORT version; /* Table version number (0). */
+diff -uN gfx/harfbuzz/src_old/hb-ot-font.cc gfx/harfbuzz/src/hb-ot-font.cc
+--- gfx/harfbuzz/src_old/hb-ot-font.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-font.cc 2016-06-05 23:49:13.433053614 +0200
+@@ -31,8 +31,11 @@
+ #include "hb-font-private.hh"
+
+ #include "hb-ot-cmap-table.hh"
++#include "hb-ot-glyf-table.hh"
++#include "hb-ot-head-table.hh"
+ #include "hb-ot-hhea-table.hh"
+ #include "hb-ot-hmtx-table.hh"
++#include "hb-ot-os2-table.hh"
+
+
+ struct hb_ot_face_metrics_accelerator_t
+@@ -40,24 +43,58 @@
+ unsigned int num_metrics;
+ unsigned int num_advances;
+ unsigned int default_advance;
++ unsigned short ascender;
++ unsigned short descender;
++ unsigned short line_gap;
++
+ const OT::_mtx *table;
+ hb_blob_t *blob;
+
+ inline void init (hb_face_t *face,
+- hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
+- unsigned int default_advance)
++ hb_tag_t _hea_tag,
++ hb_tag_t _mtx_tag,
++ hb_tag_t os2_tag)
+ {
+- this->default_advance = default_advance;
+- this->num_metrics = face->get_num_glyphs ();
++ this->default_advance = face->get_upem ();
++
++ bool got_font_extents = false;
++ if (os2_tag)
++ {
++ hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
++ const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
++#define USE_TYPO_METRICS (1u<<7)
++ if (0 != (os2->fsSelection & USE_TYPO_METRICS))
++ {
++ this->ascender = os2->sTypoAscender;
++ this->descender = os2->sTypoDescender;
++ this->line_gap = os2->sTypoLineGap;
++ got_font_extents = (this->ascender | this->descender) != 0;
++ }
++ hb_blob_destroy (os2_blob);
++ }
+
+ hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
+ const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
+ this->num_advances = _hea->numberOfLongMetrics;
++ if (!got_font_extents)
++ {
++ this->ascender = _hea->ascender;
++ this->descender = _hea->descender;
++ this->line_gap = _hea->lineGap;
++ }
+ hb_blob_destroy (_hea_blob);
+
+ this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
+- if (unlikely (!this->num_advances ||
+- 2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob)))
++
++ /* Cap num_metrics() and num_advances() based on table length. */
++ unsigned int len = hb_blob_get_length (this->blob);
++ if (unlikely (this->num_advances * 4 > len))
++ this->num_advances = len / 4;
++ this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
++
++ /* We MUST set num_metrics to zero if num_advances is zero.
++ * Our get_advance() depends on that. */
++ if (unlikely (!this->num_advances))
+ {
+ this->num_metrics = this->num_advances = 0;
+ hb_blob_destroy (this->blob);
+@@ -76,8 +113,8 @@
+ if (unlikely (glyph >= this->num_metrics))
+ {
+ /* If this->num_metrics is zero, it means we don't have the metrics table
+- * for this direction: return one EM. Otherwise, it means that the glyph
+- * index is out of bound: return zero. */
++ * for this direction: return default advance. Otherwise, it means that the
++ * glyph index is out of bound: return zero. */
+ if (this->num_metrics)
+ return 0;
+ else
+@@ -91,6 +128,79 @@
+ }
+ };
+
++struct hb_ot_face_glyf_accelerator_t
++{
++ bool short_offset;
++ unsigned int num_glyphs;
++ const OT::loca *loca;
++ const OT::glyf *glyf;
++ hb_blob_t *loca_blob;
++ hb_blob_t *glyf_blob;
++ unsigned int glyf_len;
++
++ inline void init (hb_face_t *face)
++ {
++ hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
++ const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
++ if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
++ {
++ /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
++ hb_blob_destroy (head_blob);
++ return;
++ }
++ this->short_offset = 0 == head->indexToLocFormat;
++ hb_blob_destroy (head_blob);
++
++ this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
++ this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
++ this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
++ this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
++
++ this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
++ this->glyf_len = hb_blob_get_length (this->glyf_blob);
++ }
++
++ inline void fini (void)
++ {
++ hb_blob_destroy (this->loca_blob);
++ hb_blob_destroy (this->glyf_blob);
++ }
++
++ inline bool get_extents (hb_codepoint_t glyph,
++ hb_glyph_extents_t *extents) const
++ {
++ if (unlikely (glyph >= this->num_glyphs))
++ return false;
++
++ unsigned int start_offset, end_offset;
++ if (this->short_offset)
++ {
++ start_offset = 2 * this->loca->u.shortsZ[glyph];
++ end_offset = 2 * this->loca->u.shortsZ[glyph + 1];
++ }
++ else
++ {
++ start_offset = this->loca->u.longsZ[glyph];
++ end_offset = this->loca->u.longsZ[glyph + 1];
++ }
++
++ if (start_offset > end_offset || end_offset > this->glyf_len)
++ return false;
++
++ if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
++ return true; /* Empty glyph; zero extents. */
++
++ const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
++
++ extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
++ extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
++ extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
++ extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
++
++ return true;
++ }
++};
++
+ struct hb_ot_face_cmap_accelerator_t
+ {
+ const OT::CmapSubtable *table;
+@@ -114,6 +224,7 @@
+ if (!subtable) subtable = cmap->find_subtable (0, 2);
+ if (!subtable) subtable = cmap->find_subtable (0, 1);
+ if (!subtable) subtable = cmap->find_subtable (0, 0);
++ if (!subtable) subtable = cmap->find_subtable (3, 0);
+ /* Meh. */
+ if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+@@ -157,23 +268,22 @@
+ hb_ot_face_cmap_accelerator_t cmap;
+ hb_ot_face_metrics_accelerator_t h_metrics;
+ hb_ot_face_metrics_accelerator_t v_metrics;
++ hb_ot_face_glyf_accelerator_t glyf;
+ };
+
+
+ static hb_ot_font_t *
+-_hb_ot_font_create (hb_font_t *font)
++_hb_ot_font_create (hb_face_t *face)
+ {
+ hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
+- hb_face_t *face = font->face;
+
+ if (unlikely (!ot_font))
+ return NULL;
+
+- unsigned int upem = face->get_upem ();
+-
+ ot_font->cmap.init (face);
+- ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
+- ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
++ ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
++ ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
++ ot_font->glyf.init (face);
+
+ return ot_font;
+ }
+@@ -184,6 +294,7 @@
+ ot_font->cmap.fini ();
+ ot_font->h_metrics.fini ();
+ ot_font->v_metrics.fini ();
++ ot_font->glyf.fini ();
+
+ free (ot_font);
+ }
+@@ -219,53 +330,7 @@
+ void *user_data HB_UNUSED)
+ {
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+- return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph));
+-}
+-
+-static hb_bool_t
+-hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+- void *font_data HB_UNUSED,
+- hb_codepoint_t glyph HB_UNUSED,
+- hb_position_t *x HB_UNUSED,
+- hb_position_t *y HB_UNUSED,
+- void *user_data HB_UNUSED)
+-{
+- /* We always work in the horizontal coordinates. */
+- return true;
+-}
+-
+-static hb_bool_t
+-hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+- void *font_data,
+- hb_codepoint_t glyph,
+- hb_position_t *x,
+- hb_position_t *y,
+- void *user_data HB_UNUSED)
+-{
+- /* TODO */
+- return false;
+-}
+-
+-static hb_position_t
+-hb_ot_get_glyph_h_kerning (hb_font_t *font,
+- void *font_data,
+- hb_codepoint_t left_glyph,
+- hb_codepoint_t right_glyph,
+- void *user_data HB_UNUSED)
+-{
+- /* TODO */
+- return 0;
+-}
+-
+-static hb_position_t
+-hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+- void *font_data HB_UNUSED,
+- hb_codepoint_t top_glyph HB_UNUSED,
+- hb_codepoint_t bottom_glyph HB_UNUSED,
+- void *user_data HB_UNUSED)
+-{
+- /* OpenType doesn't have vertical-kerning other than GPOS. */
+- return 0;
++ return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
+ }
+
+ static hb_bool_t
+@@ -275,69 +340,100 @@
+ hb_glyph_extents_t *extents,
+ void *user_data HB_UNUSED)
+ {
+- /* TODO */
+- return false;
++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
++ bool ret = ot_font->glyf.get_extents (glyph, extents);
++ extents->x_bearing = font->em_scale_x (extents->x_bearing);
++ extents->y_bearing = font->em_scale_y (extents->y_bearing);
++ extents->width = font->em_scale_x (extents->width);
++ extents->height = font->em_scale_y (extents->height);
++ return ret;
+ }
+
+ static hb_bool_t
+-hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+- void *font_data,
+- hb_codepoint_t glyph,
+- unsigned int point_index,
+- hb_position_t *x,
+- hb_position_t *y,
+- void *user_data HB_UNUSED)
++hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
++ void *font_data,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
+ {
+- /* TODO */
+- return false;
++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
++ metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
++ metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
++ metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
++ return true;
+ }
+
+ static hb_bool_t
+-hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
+- void *font_data,
+- hb_codepoint_t glyph,
+- char *name, unsigned int size,
+- void *user_data HB_UNUSED)
++hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
++ void *font_data,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
+ {
+- /* TODO */
+- return false;
++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
++ metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
++ metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
++ metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
++ return true;
+ }
+
+-static hb_bool_t
+-hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+- void *font_data,
+- const char *name, int len, /* -1 means nul-terminated */
+- hb_codepoint_t *glyph,
+- void *user_data HB_UNUSED)
++static hb_font_funcs_t *static_ot_funcs = NULL;
++
++#ifdef HB_USE_ATEXIT
++static
++void free_static_ot_funcs (void)
+ {
+- /* TODO */
+- return false;
++ hb_font_funcs_destroy (static_ot_funcs);
+ }
+-
++#endif
+
+ static hb_font_funcs_t *
+ _hb_ot_get_font_funcs (void)
+ {
+- static const hb_font_funcs_t ot_ffuncs = {
+- HB_OBJECT_HEADER_STATIC,
++retry:
++ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
+
+- true, /* immutable */
++ if (unlikely (!funcs))
++ {
++ funcs = hb_font_funcs_create ();
+
+- {
+-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
+- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+-#undef HB_FONT_FUNC_IMPLEMENT
++ hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
++ hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
++ hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
++ hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
++ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
++ //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
++ //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
++ //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
++ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
++ hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
++ //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
++ //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
++ //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
++
++ hb_font_funcs_make_immutable (funcs);
++
++ if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
++ hb_font_funcs_destroy (funcs);
++ goto retry;
+ }
++
++#ifdef HB_USE_ATEXIT
++ atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
++#endif
+ };
+
+- return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
++ return funcs;
+ }
+
+
++/**
++ * hb_ot_font_set_funcs:
++ *
++ * Since: 0.9.28
++ **/
+ void
+ hb_ot_font_set_funcs (hb_font_t *font)
+ {
+- hb_ot_font_t *ot_font = _hb_ot_font_create (font);
++ hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
+ if (unlikely (!ot_font))
+ return;
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-font.h gfx/harfbuzz/src/hb-ot-font.h
+--- gfx/harfbuzz/src_old/hb-ot-font.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-font.h 2016-06-05 23:49:14.679046863 +0200
+@@ -24,6 +24,10 @@
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
+ */
+
++#ifndef HB_OT_H_IN
++#error "Include <hb-ot.h> instead."
++#endif
++
+ #ifndef HB_OT_FONT_H
+ #define HB_OT_FONT_H
+
+@@ -32,7 +36,7 @@
+ HB_BEGIN_DECLS
+
+
+-void
++HB_EXTERN void
+ hb_ot_font_set_funcs (hb_font_t *font);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-glyf-table.hh gfx/harfbuzz/src/hb-ot-glyf-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-glyf-table.hh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-glyf-table.hh 2016-06-05 23:49:15.900040281 +0200
+@@ -0,0 +1,104 @@
++/*
++ * Copyright © 2015 Google, Inc.
++ *
++ * This is part of HarfBuzz, a text shaping library.
++ *
++ * Permission is hereby granted, without written agreement and without
++ * license or royalty fees, to use, copy, modify, and distribute this
++ * software and its documentation for any purpose, provided that the
++ * above copyright notice and the following two paragraphs appear in
++ * all copies of this software.
++ *
++ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
++ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
++ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ *
++ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
++ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
++ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
++ *
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_GLYF_TABLE_HH
++#define HB_OT_GLYF_TABLE_HH
++
++#include "hb-open-type-private.hh"
++
++
++namespace OT {
++
++
++/*
++ * loca -- Index to Location
++ */
++
++#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
++
++
++struct loca
++{
++ static const hb_tag_t tableTag = HB_OT_TAG_loca;
++
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
++ TRACE_SANITIZE (this);
++ return_trace (true);
++ }
++
++ public:
++ union {
++ USHORT shortsZ[VAR]; /* Location offset divided by 2. */
++ ULONG longsZ[VAR]; /* Location offset. */
++ } u;
++ DEFINE_SIZE_ARRAY (0, u.longsZ);
++};
++
++
++/*
++ * glyf -- TrueType Glyph Data
++ */
++
++#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
++
++
++struct glyf
++{
++ static const hb_tag_t tableTag = HB_OT_TAG_glyf;
++
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
++ TRACE_SANITIZE (this);
++ /* We don't check for anything specific here. The users of the
++ * struct do all the hard work... */
++ return_trace (true);
++ }
++
++ public:
++ BYTE dataX[VAR]; /* Glyphs data. */
++
++ DEFINE_SIZE_ARRAY (0, dataX);
++};
++
++struct glyfGlyphHeader
++{
++ SHORT numberOfContours; /* If the number of contours is
++ * greater than or equal to zero,
++ * this is a simple glyph; if negative,
++ * this is a composite glyph. */
++ SHORT xMin; /* Minimum x for coordinate data. */
++ SHORT yMin; /* Minimum y for coordinate data. */
++ SHORT xMax; /* Maximum x for coordinate data. */
++ SHORT yMax; /* Maximum y for coordinate data. */
++
++ DEFINE_SIZE_STATIC (10);
++};
++
++} /* namespace OT */
++
++
++#endif /* HB_OT_GLYF_TABLE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-head-table.hh gfx/harfbuzz/src/hb-ot-head-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-head-table.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-head-table.hh 2016-06-05 23:49:17.080033892 +0200
+@@ -45,15 +45,19 @@
+ {
+ static const hb_tag_t tableTag = HB_OT_TAG_head;
+
+- inline unsigned int get_upem (void) const {
++ inline unsigned int get_upem (void) const
++ {
+ unsigned int upem = unitsPerEm;
+ /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
+ return 16 <= upem && upem <= 16384 ? upem : 1000;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
++ return_trace (c->check_struct (this) &&
++ version.major == 1 &&
++ magicNumber == 0x5F0F3CF5u);
+ }
+
+ protected:
+@@ -136,9 +140,10 @@
+ * 2: Like 1 but also contains neutrals;
+ * -1: Only strongly right to left;
+ * -2: Like -1 but also contains neutrals. */
++ public:
+ SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */
+ SHORT glyphDataFormat; /* 0 for current format. */
+- public:
++
+ DEFINE_SIZE_STATIC (54);
+ };
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-hhea-table.hh gfx/harfbuzz/src/hb-ot-hhea-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-hhea-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-hhea-table.hh 2016-06-05 23:49:18.320027217 +0200
+@@ -49,9 +49,10 @@
+ static const hb_tag_t hheaTag = HB_OT_TAG_hhea;
+ static const hb_tag_t vheaTag = HB_OT_TAG_vhea;
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
++ return_trace (c->check_struct (this) && likely (version.major == 1));
+ }
+
+ public:
+diff -uN gfx/harfbuzz/src_old/hb-ot-hmtx-table.hh gfx/harfbuzz/src/hb-ot-hmtx-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-hmtx-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-hmtx-table.hh 2016-06-05 23:49:19.601020309 +0200
+@@ -57,11 +57,12 @@
+ static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
+ static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ /* We don't check for anything specific here. The users of the
+ * struct do all the hard work... */
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ public:
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout.cc gfx/harfbuzz/src/hb-ot-layout.cc
+--- gfx/harfbuzz/src_old/hb-ot-layout.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout.cc 2016-06-05 23:49:31.325957413 +0200
+@@ -28,6 +28,7 @@
+ * Google Author(s): Behdad Esfahbod
+ */
+
++#include "hb-open-type-private.hh"
+ #include "hb-ot-layout-private.hh"
+
+ #include "hb-ot-layout-gdef-table.hh"
+@@ -84,9 +85,9 @@
+ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
+ {
+ for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+- layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
++ layout->gsub_accels[i].fini ();
+ for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+- layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));
++ layout->gpos_accels[i].fini ();
+
+ free (layout->gsub_accels);
+ free (layout->gpos_accels);
+@@ -128,6 +129,11 @@
+ return _get_gdef (face).has_glyph_classes ();
+ }
+
++/**
++ * hb_ot_layout_get_glyph_class:
++ *
++ * Since: 0.9.7
++ **/
+ hb_ot_layout_glyph_class_t
+ hb_ot_layout_get_glyph_class (hb_face_t *face,
+ hb_codepoint_t glyph)
+@@ -135,6 +141,11 @@
+ return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
+ }
+
++/**
++ * hb_ot_layout_get_glyphs_in_class:
++ *
++ * Since: 0.9.7
++ **/
+ void
+ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
+ hb_ot_layout_glyph_class_t klass,
+@@ -285,6 +296,28 @@
+ return g.get_feature_tags (start_offset, feature_count, feature_tags);
+ }
+
++hb_bool_t
++hb_ot_layout_table_find_feature (hb_face_t *face,
++ hb_tag_t table_tag,
++ hb_tag_t feature_tag,
++ unsigned int *feature_index)
++{
++ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
++ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
++
++ unsigned int num_features = g.get_feature_count ();
++ for (unsigned int i = 0; i < num_features; i++)
++ {
++ if (feature_tag == g.get_feature_tag (i)) {
++ if (feature_index) *feature_index = i;
++ return true;
++ }
++ }
++
++ if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
++ return false;
++}
++
+
+ unsigned int
+ hb_ot_layout_script_get_language_tags (hb_face_t *face,
+@@ -335,6 +368,11 @@
+ NULL);
+ }
+
++/**
++ * hb_ot_layout_language_get_required_feature:
++ *
++ * Since: 0.9.30
++ **/
+ hb_bool_t
+ hb_ot_layout_language_get_required_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+@@ -419,6 +457,11 @@
+ return false;
+ }
+
++/**
++ * hb_ot_layout_feature_get_lookups:
++ *
++ * Since: 0.9.7
++ **/
+ unsigned int
+ hb_ot_layout_feature_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+@@ -433,6 +476,11 @@
+ return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+ }
+
++/**
++ * hb_ot_layout_table_get_lookup_count:
++ *
++ * Since: 0.9.22
++ **/
+ unsigned int
+ hb_ot_layout_table_get_lookup_count (hb_face_t *face,
+ hb_tag_t table_tag)
+@@ -590,6 +638,11 @@
+ }
+ }
+
++/**
++ * hb_ot_layout_collect_lookups:
++ *
++ * Since: 0.9.8
++ **/
+ void
+ hb_ot_layout_collect_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+@@ -631,6 +684,11 @@
+ }
+ }
+
++/**
++ * hb_ot_layout_lookup_collect_glyphs:
++ *
++ * Since: 0.9.7
++ **/
+ void
+ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
+ hb_tag_t table_tag,
+@@ -676,6 +734,11 @@
+ return &_get_gsub (face) != &OT::Null(OT::GSUB);
+ }
+
++/**
++ * hb_ot_layout_lookup_would_substitute:
++ *
++ * Since: 0.9.7
++ **/
+ hb_bool_t
+ hb_ot_layout_lookup_would_substitute (hb_face_t *face,
+ unsigned int lookup_index,
+@@ -695,11 +758,11 @@
+ hb_bool_t zero_context)
+ {
+ if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
+- OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
++ OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
+
+ const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+
+- return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
++ return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
+ }
+
+ void
+@@ -714,6 +777,11 @@
+ OT::GSUB::substitute_finish (font, buffer);
+ }
+
++/**
++ * hb_ot_layout_lookup_substitute_closure:
++ *
++ * Since: 0.9.7
++ **/
+ void
+ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
+ unsigned int lookup_index,
+@@ -748,6 +816,11 @@
+ OT::GPOS::position_finish (font, buffer);
+ }
+
++/**
++ * hb_ot_layout_get_size_params:
++ *
++ * Since: 0.9.10
++ **/
+ hb_bool_t
+ hb_ot_layout_get_size_params (hb_face_t *face,
+ unsigned int *design_size, /* OUT. May be NULL */
+@@ -829,28 +902,82 @@
+ };
+
+
+-template <typename Lookup>
+-static inline bool apply_once (OT::hb_apply_context_t *c,
+- const Lookup &lookup)
++template <typename Obj>
++static inline bool
++apply_forward (OT::hb_apply_context_t *c,
++ const Obj &obj,
++ const hb_ot_layout_lookup_accelerator_t &accel)
+ {
+- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
+- return false;
+- return lookup.dispatch (c);
++ bool ret = false;
++ hb_buffer_t *buffer = c->buffer;
++ while (buffer->idx < buffer->len && !buffer->in_error)
++ {
++ if (accel.may_have (buffer->cur().codepoint) &&
++ (buffer->cur().mask & c->lookup_mask) &&
++ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
++ obj.apply (c))
++ ret = true;
++ else
++ buffer->next_glyph ();
++ }
++ return ret;
+ }
+
+-template <typename Proxy>
++template <typename Obj>
+ static inline bool
++apply_backward (OT::hb_apply_context_t *c,
++ const Obj &obj,
++ const hb_ot_layout_lookup_accelerator_t &accel)
++{
++ bool ret = false;
++ hb_buffer_t *buffer = c->buffer;
++ do
++ {
++ if (accel.may_have (buffer->cur().codepoint) &&
++ (buffer->cur().mask & c->lookup_mask) &&
++ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
++ obj.apply (c))
++ ret = true;
++ /* The reverse lookup doesn't "advance" cursor (for good reason). */
++ buffer->idx--;
++
++ }
++ while ((int) buffer->idx >= 0);
++ return ret;
++}
++
++struct hb_apply_forward_context_t :
++ OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY>
++{
++ inline const char *get_name (void) { return "APPLY_FWD"; }
++ template <typename T>
++ inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
++ static return_t default_return_value (void) { return false; }
++ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
++
++ hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
++ const hb_ot_layout_lookup_accelerator_t &accel_) :
++ c (c_),
++ accel (accel_),
++ debug_depth (0) {}
++
++ OT::hb_apply_context_t *c;
++ const hb_ot_layout_lookup_accelerator_t &accel;
++ unsigned int debug_depth;
++};
++
++template <typename Proxy>
++static inline void
+ apply_string (OT::hb_apply_context_t *c,
+ const typename Proxy::Lookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+ {
+- bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+
+ if (unlikely (!buffer->len || !c->lookup_mask))
+- return false;
++ return;
+
+- c->set_lookup (lookup);
++ c->set_lookup_props (lookup.get_props ());
+
+ if (likely (!lookup.is_reverse ()))
+ {
+@@ -859,21 +986,20 @@
+ buffer->clear_output ();
+ buffer->idx = 0;
+
+- while (buffer->idx < buffer->len)
++ bool ret;
++ if (lookup.get_subtable_count () == 1)
+ {
+- if (accel.digest.may_have (buffer->cur().codepoint) &&
+- (buffer->cur().mask & c->lookup_mask) &&
+- apply_once (c, lookup))
+- ret = true;
+- else
+- buffer->next_glyph ();
++ hb_apply_forward_context_t c_forward (c, accel);
++ ret = lookup.dispatch (&c_forward);
+ }
++ else
++ ret = apply_forward (c, lookup, accel);
+ if (ret)
+ {
+ if (!Proxy::inplace)
+ buffer->swap_buffers ();
+ else
+- assert (!buffer->has_separate_output ());
++ assert (!buffer->has_separate_output ());
+ }
+ }
+ else
+@@ -882,20 +1008,9 @@
+ if (Proxy::table_index == 0)
+ buffer->remove_output ();
+ buffer->idx = buffer->len - 1;
+- do
+- {
+- if (accel.digest.may_have (buffer->cur().codepoint) &&
+- (buffer->cur().mask & c->lookup_mask) &&
+- apply_once (c, lookup))
+- ret = true;
+- /* The reverse lookup doesn't "advance" cursor (for good reason). */
+- buffer->idx--;
+
+- }
+- while ((int) buffer->idx >= 0);
++ apply_backward (c, lookup, accel);
+ }
+-
+- return ret;
+ }
+
+ template <typename Proxy>
+@@ -914,11 +1029,14 @@
+ for (; i < stage->last_lookup; i++)
+ {
+ unsigned int lookup_index = lookups[table_index][i].index;
++ if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
++ c.set_lookup_index (lookup_index);
+ c.set_lookup_mask (lookups[table_index][i].mask);
+ c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+ apply_string<Proxy> (&c,
+ proxy.table.get_lookup (lookup_index),
+ proxy.accels[lookup_index]);
++ (void) buffer->message (font, "end lookup %d", lookup_index);
+ }
+
+ if (stage->pause_func)
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-common-private.hh gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-common-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-common-private.hh 2016-06-05 23:49:21.127012094 +0200
+@@ -34,12 +34,24 @@
+ #include "hb-set-private.hh"
+
+
++#ifndef HB_MAX_NESTING_LEVEL
++#define HB_MAX_NESTING_LEVEL 6
++#endif
++#ifndef HB_MAX_CONTEXT_LENGTH
++#define HB_MAX_CONTEXT_LENGTH 64
++#endif
++
++
+ namespace OT {
+
+
++#define TRACE_DISPATCH(this, format) \
++ hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
++ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
++ "format %d", (int) format);
++
++
+ #define NOT_COVERED ((unsigned int) -1)
+-#define MAX_NESTING_LEVEL 8
+-#define MAX_CONTEXT_LENGTH 64
+
+
+
+@@ -63,12 +75,13 @@
+
+ struct sanitize_closure_t {
+ hb_tag_t tag;
+- void *list_base;
++ const void *list_base;
+ };
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+ const sanitize_closure_t closure = {tag, base};
+- return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
++ return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+ }
+
+ Tag tag; /* 4-byte Tag identifier */
+@@ -121,9 +134,10 @@
+ inline const Type& operator [] (unsigned int i) const
+ { return this+RecordArrayOf<Type>::operator [](i).offset; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
++ return_trace (RecordArrayOf<Type>::sanitize (c, this));
+ }
+ };
+
+@@ -134,9 +148,10 @@
+ return g < start ? -1 : g <= end ? 0 : +1 ;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ inline bool intersects (const hb_set_t *glyphs) const {
+@@ -199,9 +214,10 @@
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+- const Record<LangSys>::sanitize_closure_t * = NULL) {
++ const Record<LangSys>::sanitize_closure_t * = NULL) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
++ return_trace (c->check_struct (this) && featureIndex.sanitize (c));
+ }
+
+ Offset<> lookupOrderZ; /* = Null (reserved for an offset to a
+@@ -238,9 +254,10 @@
+ inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+- const Record<Script>::sanitize_closure_t * = NULL) {
++ const Record<Script>::sanitize_closure_t * = NULL) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
++ return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
+ }
+
+ protected:
+@@ -260,9 +277,10 @@
+ /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+ struct FeatureParamsSize
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
++ if (unlikely (!c->check_struct (this))) return_trace (false);
+
+ /* This subtable has some "history", if you will. Some earlier versions of
+ * Adobe tools calculated the offset of the FeatureParams sutable from the
+@@ -314,19 +332,19 @@
+ */
+
+ if (!designSize)
+- return TRACE_RETURN (false);
++ return_trace (false);
+ else if (subfamilyID == 0 &&
+ subfamilyNameID == 0 &&
+ rangeStart == 0 &&
+ rangeEnd == 0)
+- return TRACE_RETURN (true);
++ return_trace (true);
+ else if (designSize < rangeStart ||
+ designSize > rangeEnd ||
+ subfamilyNameID < 256 ||
+ subfamilyNameID > 32767)
+- return TRACE_RETURN (false);
++ return_trace (false);
+ else
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ USHORT designSize; /* Represents the design size in 720/inch
+@@ -371,11 +389,12 @@
+ /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
+ struct FeatureParamsStylisticSet
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ /* Right now minorVersion is at zero. Which means, any table supports
+ * the uiNameID field. */
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ USHORT version; /* (set to 0): This corresponds to a “minor”
+@@ -404,10 +423,11 @@
+ /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
+ struct FeatureParamsCharacterVariants
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- characters.sanitize (c));
++ return_trace (c->check_struct (this) &&
++ characters.sanitize (c));
+ }
+
+ USHORT format; /* Format number is set to 0. */
+@@ -444,15 +464,16 @@
+
+ struct FeatureParams
+ {
+- inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
++ inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
++ {
+ TRACE_SANITIZE (this);
+ if (tag == HB_TAG ('s','i','z','e'))
+- return TRACE_RETURN (u.size.sanitize (c));
++ return_trace (u.size.sanitize (c));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+- return TRACE_RETURN (u.stylisticSet.sanitize (c));
++ return_trace (u.stylisticSet.sanitize (c));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+- return TRACE_RETURN (u.characterVariants.sanitize (c));
+- return TRACE_RETURN (true);
++ return_trace (u.characterVariants.sanitize (c));
++ return_trace (true);
+ }
+
+ inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
+@@ -486,10 +507,11 @@
+ { return this+featureParams; }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+- const Record<Feature>::sanitize_closure_t *closure) {
++ const Record<Feature>::sanitize_closure_t *closure) const
++ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ /* Some earlier versions of Adobe tools calculated the offset of the
+ * FeatureParams subtable from the beginning of the FeatureList table!
+@@ -504,10 +526,10 @@
+
+ OffsetTo<FeatureParams> orig_offset = featureParams;
+ if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ if (likely (orig_offset.is_null ()))
+- return TRACE_RETURN (true);
++ return_trace (true);
+
+ if (featureParams == 0 && closure &&
+ closure->tag == HB_TAG ('s','i','z','e') &&
+@@ -522,10 +544,13 @@
+ if (new_offset == new_offset_int &&
+ c->try_set (&featureParams, new_offset) &&
+ !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+- return TRACE_RETURN (false);
++ return_trace (false);
++
++ if (c->edit_count > 1)
++ c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
+ }
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ OffsetTo<FeatureParams>
+@@ -557,10 +582,26 @@
+ DEFINE_SIZE_STATIC (2);
+ };
+
++} /* namespace OT */
++/* This has to be outside the namespace. */
++HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
++namespace OT {
++
+ struct Lookup
+ {
+ inline unsigned int get_subtable_count (void) const { return subTable.len; }
+
++ template <typename SubTableType>
++ inline const SubTableType& get_subtable (unsigned int i) const
++ { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
++
++ template <typename SubTableType>
++ inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
++ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
++ template <typename SubTableType>
++ inline OffsetArrayOf<SubTableType>& get_subtables (void)
++ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
++
+ inline unsigned int get_type (void) const { return lookupType; }
+
+ /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
+@@ -577,36 +618,52 @@
+ return flag;
+ }
+
++ template <typename SubTableType, typename context_t>
++ inline typename context_t::return_t dispatch (context_t *c) const
++ {
++ unsigned int lookup_type = get_type ();
++ TRACE_DISPATCH (this, lookup_type);
++ unsigned int count = get_subtable_count ();
++ for (unsigned int i = 0; i < count; i++) {
++ typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
++ if (c->stop_sublookup_iteration (r))
++ return_trace (r);
++ }
++ return_trace (c->default_return_value ());
++ }
++
+ inline bool serialize (hb_serialize_context_t *c,
+ unsigned int lookup_type,
+ uint32_t lookup_props,
+ unsigned int num_subtables)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ lookupType.set (lookup_type);
+ lookupFlag.set (lookup_props & 0xFFFFu);
+- if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
++ if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
+ if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+ {
+ USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ markFilteringSet.set (lookup_props >> 16);
+ }
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ /* Real sanitize of the subtables is done by GSUB/GPOS/... */
+- if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
++ if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+ if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+ {
+- USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+- if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
++ const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
++ if (!markFilteringSet.sanitize (c)) return_trace (false);
+ }
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
++ private:
+ USHORT lookupType; /* Different enumerations for GSUB and GPOS */
+ USHORT lookupFlag; /* Lookup qualifiers */
+ ArrayOf<Offset<> >
+@@ -642,18 +699,19 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ glyphArray.len.set (num_glyphs);
+- if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend (glyphArray))) return_trace (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ glyphArray[i] = glyphs[i];
+ glyphs.advance (num_glyphs);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (glyphArray.sanitize (c));
++ return_trace (glyphArray.sanitize (c));
+ }
+
+ inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+@@ -710,16 +768,16 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+
+- if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
++ if (unlikely (!num_glyphs)) return_trace (true);
+
+ unsigned int num_ranges = 1;
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (glyphs[i - 1] + 1 != glyphs[i])
+ num_ranges++;
+ rangeRecord.len.set (num_ranges);
+- if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend (rangeRecord))) return_trace (false);
+
+ unsigned int range = 0;
+ rangeRecord[range].start = glyphs[0];
+@@ -734,12 +792,13 @@
+ rangeRecord[range].end = glyphs[i];
+ }
+ glyphs.advance (num_glyphs);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (rangeRecord.sanitize (c));
++ return_trace (rangeRecord.sanitize (c));
+ }
+
+ inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+@@ -819,26 +878,27 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ unsigned int num_ranges = 1;
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (glyphs[i - 1] + 1 != glyphs[i])
+ num_ranges++;
+ u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
+- case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
+- default:return TRACE_RETURN (false);
++ case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
++ case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
++ default:return_trace (false);
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.sanitize (c));
++ case 2: return_trace (u.format2.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -938,14 +998,16 @@
+ private:
+ inline unsigned int get_class (hb_codepoint_t glyph_id) const
+ {
+- if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
+- return classValue[glyph_id - startGlyph];
++ unsigned int i = (unsigned int) (glyph_id - startGlyph);
++ if (unlikely (i < classValue.len))
++ return classValue[i];
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
++ return_trace (c->check_struct (this) && classValue.sanitize (c));
+ }
+
+ template <typename set_t>
+@@ -994,14 +1056,15 @@
+ inline unsigned int get_class (hb_codepoint_t glyph_id) const
+ {
+ int i = rangeRecord.bsearch (glyph_id);
+- if (i != -1)
++ if (unlikely (i != -1))
+ return rangeRecord[i].value;
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (rangeRecord.sanitize (c));
++ return_trace (rangeRecord.sanitize (c));
+ }
+
+ template <typename set_t>
+@@ -1056,13 +1119,14 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.sanitize (c));
++ case 2: return_trace (u.format2.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -1148,9 +1212,10 @@
+ return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
++ return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+ }
+
+ protected:
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-gdef-table.hh gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-gdef-table.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh 2016-06-05 23:49:22.476004876 +0200
+@@ -71,9 +71,10 @@
+ return points.len;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
+ }
+
+ protected:
+@@ -101,9 +102,10 @@
+ return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ protected:
+@@ -127,9 +129,10 @@
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ protected:
+@@ -150,9 +153,10 @@
+ font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
++ return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
+ }
+
+ protected:
+@@ -178,14 +182,15 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- case 3: return TRACE_RETURN (u.format3.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.sanitize (c));
++ case 2: return_trace (u.format2.sanitize (c));
++ case 3: return_trace (u.format3.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -219,9 +224,10 @@
+ return carets.len;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (carets.sanitize (c, this));
++ return_trace (carets.sanitize (c, this));
+ }
+
+ protected:
+@@ -253,9 +259,10 @@
+ return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
+ }
+
+ protected:
+@@ -275,9 +282,10 @@
+ inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+ { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this));
+ }
+
+ protected:
+@@ -299,12 +307,13 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -364,15 +373,16 @@
+ inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+ { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (version.sanitize (c) &&
+- likely (version.major == 1) &&
+- glyphClassDef.sanitize (c, this) &&
+- attachList.sanitize (c, this) &&
+- ligCaretList.sanitize (c, this) &&
+- markAttachClassDef.sanitize (c, this) &&
+- (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
++ return_trace (version.sanitize (c) &&
++ likely (version.major == 1) &&
++ glyphClassDef.sanitize (c, this) &&
++ attachList.sanitize (c, this) &&
++ ligCaretList.sanitize (c, this) &&
++ markAttachClassDef.sanitize (c, this) &&
++ (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+ }
+
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-gpos-table.hh gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-gpos-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh 2016-06-05 23:49:23.921997102 +0200
+@@ -146,7 +146,8 @@
+ }
+
+ private:
+- inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
++ inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
++ {
+ unsigned int format = *this;
+
+ if (format & xPlacement) values++;
+@@ -177,41 +178,44 @@
+ return (format & devices) != 0;
+ }
+
+- inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
++ inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
++ return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+ }
+
+- inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
++ inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
++ {
+ TRACE_SANITIZE (this);
+ unsigned int len = get_len ();
+
+- if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
++ if (!c->check_array (values, get_size (), count)) return_trace (false);
+
+- if (!has_device ()) return TRACE_RETURN (true);
++ if (!has_device ()) return_trace (true);
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+- return TRACE_RETURN (false);
++ return_trace (false);
+ values += len;
+ }
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
+- inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
++ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
++ {
+ TRACE_SANITIZE (this);
+
+- if (!has_device ()) return TRACE_RETURN (true);
++ if (!has_device ()) return_trace (true);
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+- return TRACE_RETURN (false);
++ return_trace (false);
+ values += stride;
+ }
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+ };
+
+@@ -225,9 +229,10 @@
+ *y = font->em_scale_y (yCoordinate);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ protected:
+@@ -254,9 +259,10 @@
+ *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ protected:
+@@ -282,9 +288,10 @@
+ *y += (this+yDeviceTable).get_x_delta (font);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
++ return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+ }
+
+ protected:
+@@ -317,14 +324,15 @@
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- case 3: return TRACE_RETURN (u.format3.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.sanitize (c));
++ case 2: return_trace (u.format2.sanitize (c));
++ case 3: return_trace (u.format3.sanitize (c));
++ default:return_trace (true);
+ }
+ }
+
+@@ -349,15 +357,16 @@
+ return this+matrixZ[row * cols + col];
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
++ inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
++ {
+ TRACE_SANITIZE (this);
+- if (!c->check_struct (this)) return TRACE_RETURN (false);
+- if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
++ if (!c->check_struct (this)) return_trace (false);
++ if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+ unsigned int count = rows * cols;
+- if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
++ if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
+ for (unsigned int i = 0; i < count; i++)
+- if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (!matrixZ[i].sanitize (c, this)) return_trace (false);
++ return_trace (true);
+ }
+
+ USHORT rows; /* Number of rows */
+@@ -374,9 +383,10 @@
+ {
+ friend struct MarkArray;
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
++ return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
+ }
+
+ protected:
+@@ -405,7 +415,7 @@
+ const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ /* If this subtable doesn't have an anchor for this base and this class,
+ * return false such that the subsequent subtables have a chance at it. */
+- if (unlikely (!found)) return TRACE_RETURN (false);
++ if (unlikely (!found)) return_trace (false);
+
+ hb_position_t mark_x, mark_y, base_x, base_y;
+
+@@ -416,14 +426,16 @@
+ o.x_offset = base_x - mark_x;
+ o.y_offset = base_y - mark_y;
+ o.attach_lookback() = buffer->idx - glyph_pos;
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+
+ buffer->idx++;
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
++ return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
+ }
+ };
+
+@@ -448,18 +460,21 @@
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ valueFormat.apply_value (c->font, c->direction, this,
+ values, buffer->cur_pos());
+
+ buffer->idx++;
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
++ return_trace (c->check_struct (this) &&
++ coverage.sanitize (c, this) &&
++ valueFormat.sanitize_value (c, this, values));
+ }
+
+ protected:
+@@ -494,21 +509,24 @@
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+- if (likely (index >= valueCount)) return TRACE_RETURN (false);
++ if (likely (index >= valueCount)) return_trace (false);
+
+ valueFormat.apply_value (c->font, c->direction, this,
+ &values[index * valueFormat.get_len ()],
+ buffer->cur_pos());
+
+ buffer->idx++;
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
++ return_trace (c->check_struct (this) &&
++ coverage.sanitize (c, this) &&
++ valueFormat.sanitize_values (c, this, values, valueCount));
+ }
+
+ protected:
+@@ -531,20 +549,11 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- case 2: return TRACE_RETURN (c->dispatch (u.format2));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ case 2: return_trace (c->dispatch (u.format2));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -602,12 +611,24 @@
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+- const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
++ const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
+ unsigned int count = len;
+- for (unsigned int i = 0; i < count; i++)
++
++ /* Hand-coded bsearch. */
++ if (unlikely (!count))
++ return_trace (false);
++ hb_codepoint_t x = buffer->info[pos].codepoint;
++ int min = 0, max = (int) count - 1;
++ while (min <= max)
+ {
+- /* TODO bsearch */
+- if (buffer->info[pos].codepoint == record->secondGlyph)
++ int mid = (min + max) / 2;
++ const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
++ hb_codepoint_t mid_x = record->secondGlyph;
++ if (x < mid_x)
++ max = mid - 1;
++ else if (x > mid_x)
++ min = mid + 1;
++ else
+ {
+ valueFormats[0].apply_value (c->font, c->direction, this,
+ &record->values[0], buffer->cur_pos());
+@@ -616,30 +637,30 @@
+ if (len2)
+ pos++;
+ buffer->idx = pos;
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+- record = &StructAtOffset<PairValueRecord> (record, record_size);
+ }
+
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ struct sanitize_closure_t {
+- void *base;
+- ValueFormat *valueFormats;
++ const void *base;
++ const ValueFormat *valueFormats;
+ unsigned int len1; /* valueFormats[0].get_len() */
+ unsigned int stride; /* 1 + len1 + len2 */
+ };
+
+- inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
++ inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
++ {
+ TRACE_SANITIZE (this);
+ if (!(c->check_struct (this)
+- && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
++ && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
+
+ unsigned int count = len;
+- PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+- return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
+- && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
++ const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
++ return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
++ closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
+ }
+
+ protected:
+@@ -670,20 +691,22 @@
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+-
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+- if (!skippy_iter.next ()) return TRACE_RETURN (false);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
++ if (!skippy_iter.next ()) return_trace (false);
+
+- return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
++ return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+
++ if (!c->check_struct (this)) return_trace (false);
++
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ PairSet::sanitize_closure_t closure = {
+@@ -693,7 +716,7 @@
+ 1 + len1 + len2
+ };
+
+- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
++ return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
+ }
+
+ protected:
+@@ -719,7 +742,7 @@
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+- /* (this+coverage).add_coverage (c->input); // Don't need this. */
++ (this+coverage).add_coverage (c->input);
+
+ unsigned int count1 = class1Count;
+ const ClassDef &klass1 = this+classDef1;
+@@ -741,13 +764,12 @@
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+-
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+- if (!skippy_iter.next ()) return TRACE_RETURN (false);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
++ if (!skippy_iter.next ()) return_trace (false);
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+@@ -755,7 +777,7 @@
+
+ unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+ unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+- if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
++ if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
+
+ const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
+ valueFormat1.apply_value (c->font, c->direction, this,
+@@ -767,24 +789,25 @@
+ if (len2)
+ buffer->idx++;
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ if (!(c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && classDef1.sanitize (c, this)
+- && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
++ && classDef2.sanitize (c, this))) return_trace (false);
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int stride = len1 + len2;
+ unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
+ unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+- return TRACE_RETURN (c->check_array (values, record_size, count) &&
+- valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+- valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
++ return_trace (c->check_array (values, record_size, count) &&
++ valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
++ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+ }
+
+ protected:
+@@ -823,20 +846,11 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- case 2: return TRACE_RETURN (c->dispatch (u.format2));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ case 2: return_trace (c->dispatch (u.format2));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -853,9 +867,10 @@
+ {
+ friend struct CursivePosFormat1;
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
++ return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
+ }
+
+ protected:
+@@ -871,6 +886,9 @@
+ DEFINE_SIZE_STATIC (4);
+ };
+
++static void
++reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
++
+ struct CursivePosFormat1
+ {
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+@@ -890,18 +908,17 @@
+ hb_buffer_t *buffer = c->buffer;
+
+ /* We don't handle mark glyphs here. */
+- if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
+-
+- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
++ if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false);
+
+ const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
+- if (!this_record.exitAnchor) return TRACE_RETURN (false);
++ if (!this_record.exitAnchor) return_trace (false);
+
+- if (!skippy_iter.next ()) return TRACE_RETURN (false);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
++ if (!skippy_iter.next ()) return_trace (false);
+
+ const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
+- if (!next_record.entryAnchor) return TRACE_RETURN (false);
++ if (!next_record.entryAnchor) return_trace (false);
+
+ unsigned int i = buffer->idx;
+ unsigned int j = skippy_iter.idx;
+@@ -949,27 +966,48 @@
+ }
+
+ /* Cross-direction adjustment */
+- if (c->lookup_props & LookupFlag::RightToLeft) {
+- pos[i].cursive_chain() = j - i;
+- if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+- pos[i].y_offset = entry_y - exit_y;
+- else
+- pos[i].x_offset = entry_x - exit_x;
+- } else {
+- pos[j].cursive_chain() = i - j;
+- if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
+- pos[j].y_offset = exit_y - entry_y;
+- else
+- pos[j].x_offset = exit_x - entry_x;
+- }
++
++ /* We attach child to parent (think graph theory and rooted trees whereas
++ * the root stays on baseline and each node aligns itself against its
++ * parent.
++ *
++ * Optimize things for the case of RightToLeft, as that's most common in
++ * Arabinc. */
++ unsigned int child = i;
++ unsigned int parent = j;
++ hb_position_t x_offset = entry_x - exit_x;
++ hb_position_t y_offset = entry_y - exit_y;
++ if (!(c->lookup_props & LookupFlag::RightToLeft))
++ {
++ unsigned int k = child;
++ child = parent;
++ parent = k;
++ x_offset = -x_offset;
++ y_offset = -y_offset;
++ }
++
++ /* If child was already connected to someone else, walk through its old
++ * chain and reverse the link direction, such that the whole tree of its
++ * previous connection now attaches to new parent. Watch out for case
++ * where new parent is on the path from old chain...
++ */
++ reverse_cursive_minor_offset (pos, child, c->direction, parent);
++
++ pos[child].cursive_chain() = parent - child;
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
++ if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
++ pos[child].y_offset = y_offset;
++ else
++ pos[child].x_offset = x_offset;
+
+ buffer->idx = j;
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+ }
+
+ protected:
+@@ -990,18 +1028,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1037,31 +1067,36 @@
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
+- if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+ /* now we search backwards for a non-mark glyph */
+- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+ do {
+- if (!skippy_iter.prev ()) return TRACE_RETURN (false);
++ if (!skippy_iter.prev ()) return_trace (false);
+ /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
+ if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
+ skippy_iter.reject ();
+ } while (1);
+
+ /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+- if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
++ if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+
+ unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
+- if (base_index == NOT_COVERED) return TRACE_RETURN (false);
++ if (base_index == NOT_COVERED) return_trace (false);
+
+- return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
++ return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
+- markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
++ return_trace (c->check_struct (this) &&
++ markCoverage.sanitize (c, this) &&
++ baseCoverage.sanitize (c, this) &&
++ markArray.sanitize (c, this) &&
++ baseArray.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ protected:
+@@ -1089,18 +1124,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1141,26 +1168,27 @@
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
+- if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (mark_index == NOT_COVERED)) return_trace (false);
+
+ /* now we search backwards for a non-mark glyph */
+- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+- if (!skippy_iter.prev ()) return TRACE_RETURN (false);
++ if (!skippy_iter.prev ()) return_trace (false);
+
+ /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+- if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
++ if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+
+ unsigned int j = skippy_iter.idx;
+ unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
+- if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
++ if (lig_index == NOT_COVERED) return_trace (false);
+
+ const LigatureArray& lig_array = this+ligatureArray;
+ const LigatureAttach& lig_attach = lig_array[lig_index];
+
+ /* Find component to attach to */
+ unsigned int comp_count = lig_attach.rows;
+- if (unlikely (!comp_count)) return TRACE_RETURN (false);
++ if (unlikely (!comp_count)) return_trace (false);
+
+ /* We must now check whether the ligature ID of the current mark glyph
+ * is identical to the ligature ID of the found ligature. If yes, we
+@@ -1175,13 +1203,17 @@
+ else
+ comp_index = comp_count - 1;
+
+- return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
++ return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
+- markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
++ return_trace (c->check_struct (this) &&
++ markCoverage.sanitize (c, this) &&
++ ligatureCoverage.sanitize (c, this) &&
++ markArray.sanitize (c, this) &&
++ ligatureArray.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ protected:
+@@ -1210,18 +1242,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1257,14 +1281,15 @@
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
+- if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (mark1_index == NOT_COVERED)) return_trace (false);
+
+ /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+- if (!skippy_iter.prev ()) return TRACE_RETURN (false);
++ if (!skippy_iter.prev ()) return_trace (false);
+
+- if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
++ if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+
+ unsigned int j = skippy_iter.idx;
+
+@@ -1286,20 +1311,23 @@
+ }
+
+ /* Didn't match. */
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ good:
+ unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
+- if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
++ if (mark2_index == NOT_COVERED) return_trace (false);
+
+- return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
++ return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
+- mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
+- && mark2Array.sanitize (c, this, (unsigned int) classCount));
++ return_trace (c->check_struct (this) &&
++ mark1Coverage.sanitize (c, this) &&
++ mark2Coverage.sanitize (c, this) &&
++ mark1Array.sanitize (c, this) &&
++ mark2Array.sanitize (c, this, (unsigned int) classCount));
+ }
+
+ protected:
+@@ -1329,18 +1357,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1388,43 +1408,24 @@
+ inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+ {
+ TRACE_DISPATCH (this, lookup_type);
++ if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
+ switch (lookup_type) {
+- case Single: return TRACE_RETURN (u.single.dispatch (c));
+- case Pair: return TRACE_RETURN (u.pair.dispatch (c));
+- case Cursive: return TRACE_RETURN (u.cursive.dispatch (c));
+- case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c));
+- case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c));
+- case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c));
+- case Context: return TRACE_RETURN (u.context.dispatch (c));
+- case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
+- case Extension: return TRACE_RETURN (u.extension.dispatch (c));
+- default: return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
+- TRACE_SANITIZE (this);
+- if (!u.header.sub_format.sanitize (c))
+- return TRACE_RETURN (false);
+- switch (lookup_type) {
+- case Single: return TRACE_RETURN (u.single.sanitize (c));
+- case Pair: return TRACE_RETURN (u.pair.sanitize (c));
+- case Cursive: return TRACE_RETURN (u.cursive.sanitize (c));
+- case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c));
+- case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c));
+- case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c));
+- case Context: return TRACE_RETURN (u.context.sanitize (c));
+- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
+- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
+- default: return TRACE_RETURN (true);
++ case Single: return_trace (u.single.dispatch (c));
++ case Pair: return_trace (u.pair.dispatch (c));
++ case Cursive: return_trace (u.cursive.dispatch (c));
++ case MarkBase: return_trace (u.markBase.dispatch (c));
++ case MarkLig: return_trace (u.markLig.dispatch (c));
++ case MarkMark: return_trace (u.markMark.dispatch (c));
++ case Context: return_trace (u.context.dispatch (c));
++ case ChainContext: return_trace (u.chainContext.dispatch (c));
++ case Extension: return_trace (u.extension.dispatch (c));
++ default: return_trace (c->default_return_value ());
+ }
+ }
+
+ protected:
+ union {
+- struct {
+- USHORT sub_format;
+- } header;
++ USHORT sub_format;
+ SinglePos single;
+ PairPos pair;
+ CursivePos cursive;
+@@ -1436,48 +1437,37 @@
+ ExtensionPos extension;
+ } u;
+ public:
+- DEFINE_SIZE_UNION (2, header.sub_format);
++ DEFINE_SIZE_UNION (2, sub_format);
+ };
+
+
+ struct PosLookup : Lookup
+ {
+ inline const PosLookupSubTable& get_subtable (unsigned int i) const
+- { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
++ { return Lookup::get_subtable<PosLookupSubTable> (i); }
+
+ inline bool is_reverse (void) const
+ {
+ return false;
+ }
+
++ inline bool apply (hb_apply_context_t *c) const
++ {
++ TRACE_APPLY (this);
++ return_trace (dispatch (c));
++ }
++
+ inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+- c->set_recurse_func (NULL);
+- return TRACE_RETURN (dispatch (c));
++ return_trace (dispatch (c));
+ }
+
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const
+ {
+- hb_get_coverage_context_t c;
+- const Coverage *last = NULL;
+- unsigned int count = get_subtable_count ();
+- for (unsigned int i = 0; i < count; i++) {
+- const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
+- if (coverage != last) {
+- coverage->add_coverage (glyphs);
+- last = coverage;
+- }
+- }
+- }
+-
+- inline bool apply_once (hb_apply_context_t *c) const
+- {
+- TRACE_APPLY (this);
+- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
+- return TRACE_RETURN (false);
+- return TRACE_RETURN (dispatch (c));
++ hb_add_coverage_context_t<set_t> c (glyphs);
++ dispatch (&c);
+ }
+
+ static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+@@ -1487,23 +1477,13 @@
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+- {
+- unsigned int lookup_type = get_type ();
+- TRACE_DISPATCH (this, lookup_type);
+- unsigned int count = get_subtable_count ();
+- for (unsigned int i = 0; i < count; i++) {
+- typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
+- if (c->stop_sublookup_iteration (r))
+- return TRACE_RETURN (r);
+- }
+- return TRACE_RETURN (c->default_return_value ());
+- }
++ { return Lookup::dispatch<PosLookupSubTable> (c); }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
+- OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
+- return TRACE_RETURN (list.sanitize (c, this, get_type ()));
++ if (unlikely (!Lookup::sanitize (c))) return_trace (false);
++ return_trace (dispatch (c));
+ }
+ };
+
+@@ -1523,11 +1503,12 @@
+ static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
+- OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+- return TRACE_RETURN (list.sanitize (c, this));
++ if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
++ const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
++ return_trace (list.sanitize (c, this));
+ }
+ public:
+ DEFINE_SIZE_STATIC (10);
+@@ -1535,6 +1516,30 @@
+
+
+ static void
++reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
++{
++ unsigned int j = pos[i].cursive_chain();
++ if (likely (!j))
++ return;
++
++ j += i;
++
++ pos[i].cursive_chain() = 0;
++
++ /* Stop if we see new parent in the chain. */
++ if (j == new_parent)
++ return;
++
++ reverse_cursive_minor_offset (pos, j, direction, new_parent);
++
++ if (HB_DIRECTION_IS_HORIZONTAL (direction))
++ pos[j].y_offset = -pos[i].y_offset;
++ else
++ pos[j].x_offset = -pos[i].x_offset;
++
++ pos[j].cursive_chain() = i - j;
++}
++static void
+ fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+ {
+ unsigned int j = pos[i].cursive_chain();
+@@ -1596,12 +1601,14 @@
+ hb_direction_t direction = buffer->props.direction;
+
+ /* Handle cursive connections */
+- for (unsigned int i = 0; i < len; i++)
+- fix_cursive_minor_offset (pos, i, direction);
++ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
++ for (unsigned int i = 0; i < len; i++)
++ fix_cursive_minor_offset (pos, i, direction);
+
+ /* Handle attachments */
+- for (unsigned int i = 0; i < len; i++)
+- fix_mark_attachment (pos, i, direction);
++ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
++ for (unsigned int i = 0; i < len; i++)
++ fix_mark_attachment (pos, i, direction);
+ }
+
+
+@@ -1620,9 +1627,12 @@
+ const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+ const PosLookup &l = gpos.get_lookup (lookup_index);
+ unsigned int saved_lookup_props = c->lookup_props;
+- c->set_lookup (l);
+- bool ret = l.apply_once (c);
+- c->lookup_props = saved_lookup_props;
++ unsigned int saved_lookup_index = c->lookup_index;
++ c->set_lookup_index (lookup_index);
++ c->set_lookup_props (l.get_props ());
++ bool ret = l.dispatch (c);
++ c->set_lookup_index (saved_lookup_index);
++ c->set_lookup_props (saved_lookup_props);
+ return ret;
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-gsubgpos-private.hh gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-gsubgpos-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh 2016-06-05 23:49:27.351978674 +0200
+@@ -37,12 +37,6 @@
+ namespace OT {
+
+
+-
+-#define TRACE_DISPATCH(this, format) \
+- hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+- (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+- "format %d", (int) format);
+-
+ #ifndef HB_DEBUG_CLOSURE
+ #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
+ #endif
+@@ -52,11 +46,10 @@
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
+
+-struct hb_closure_context_t
++struct hb_closure_context_t :
++ hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
+ {
+ inline const char *get_name (void) { return "CLOSURE"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
+- typedef hb_void_t return_t;
+ typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+ template <typename T>
+ inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
+@@ -81,7 +74,7 @@
+
+ hb_closure_context_t (hb_face_t *face_,
+ hb_set_t *glyphs_,
+- unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
++ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+ face (face_),
+ glyphs (glyphs_),
+ recurse_func (NULL),
+@@ -102,11 +95,10 @@
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "%d glyphs", c->len);
+
+-struct hb_would_apply_context_t
++struct hb_would_apply_context_t :
++ hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
+ {
+ inline const char *get_name (void) { return "WOULD_APPLY"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
+- typedef bool return_t;
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
+ static return_t default_return_value (void) { return false; }
+@@ -140,11 +132,10 @@
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
+
+-struct hb_collect_glyphs_context_t
++struct hb_collect_glyphs_context_t :
++ hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
+ {
+ inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
+- typedef hb_void_t return_t;
+ typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+ template <typename T>
+ inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
+@@ -205,7 +196,7 @@
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+ hb_set_t *glyphs_after, /* OUT. May be NULL */
+ hb_set_t *glyphs_output, /* OUT. May be NULL */
+- unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
++ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
+ face (face_),
+ before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
+ input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
+@@ -232,18 +223,28 @@
+ #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
+ #endif
+
+-struct hb_get_coverage_context_t
++/* XXX Can we remove this? */
++
++template <typename set_t>
++struct hb_add_coverage_context_t :
++ hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
+ {
+ inline const char *get_name (void) { return "GET_COVERAGE"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
+ typedef const Coverage &return_t;
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
+ static return_t default_return_value (void) { return Null(Coverage); }
++ bool stop_sublookup_iteration (return_t r) const
++ {
++ r.add_coverage (set);
++ return false;
++ }
+
+- hb_get_coverage_context_t (void) :
++ hb_add_coverage_context_t (set_t *set_) :
++ set (set_),
+ debug_depth (0) {}
+
++ set_t *set;
+ unsigned int debug_depth;
+ };
+
+@@ -256,65 +257,12 @@
+ #define TRACE_APPLY(this) \
+ hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+- "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
++ "idx %d gid %u lookup %d", \
++ c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
+
+-struct hb_apply_context_t
++struct hb_apply_context_t :
++ hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
+ {
+- inline const char *get_name (void) { return "APPLY"; }
+- static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+- typedef bool return_t;
+- typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+- template <typename T>
+- inline return_t dispatch (const T &obj) { return obj.apply (this); }
+- static return_t default_return_value (void) { return false; }
+- bool stop_sublookup_iteration (return_t r) const { return r; }
+- return_t recurse (unsigned int lookup_index)
+- {
+- if (unlikely (nesting_level_left == 0 || !recurse_func))
+- return default_return_value ();
+-
+- nesting_level_left--;
+- bool ret = recurse_func (this, lookup_index);
+- nesting_level_left++;
+- return ret;
+- }
+-
+- unsigned int table_index; /* GSUB/GPOS */
+- hb_font_t *font;
+- hb_face_t *face;
+- hb_buffer_t *buffer;
+- hb_direction_t direction;
+- hb_mask_t lookup_mask;
+- bool auto_zwj;
+- recurse_func_t recurse_func;
+- unsigned int nesting_level_left;
+- unsigned int lookup_props;
+- const GDEF &gdef;
+- bool has_glyph_classes;
+- unsigned int debug_depth;
+-
+-
+- hb_apply_context_t (unsigned int table_index_,
+- hb_font_t *font_,
+- hb_buffer_t *buffer_) :
+- table_index (table_index_),
+- font (font_), face (font->face), buffer (buffer_),
+- direction (buffer_->props.direction),
+- lookup_mask (1),
+- auto_zwj (true),
+- recurse_func (NULL),
+- nesting_level_left (MAX_NESTING_LEVEL),
+- lookup_props (0),
+- gdef (*hb_ot_layout_from_face (face)->gdef),
+- has_glyph_classes (gdef.has_glyph_classes ()),
+- debug_depth (0) {}
+-
+- inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+- inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+- inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+- inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+- inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
+-
+ struct matcher_t
+ {
+ inline matcher_t (void) :
+@@ -373,8 +321,7 @@
+
+ if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+ (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+- (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
+- !_hb_glyph_info_ligated (&info)))
++ (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
+ return SKIP_MAYBE;
+
+ return SKIP_NO;
+@@ -390,43 +337,47 @@
+ const void *match_data;
+ };
+
+- struct skipping_forward_iterator_t
++ struct skipping_iterator_t
+ {
+- inline skipping_forward_iterator_t (hb_apply_context_t *c_,
+- unsigned int start_index_,
+- unsigned int num_items_,
+- bool context_match = false) :
+- idx (start_index_),
+- c (c_),
+- match_glyph_data (NULL),
+- num_items (num_items_),
+- end (c->buffer->len)
++ inline void init (hb_apply_context_t *c_, bool context_match = false)
+ {
++ c = c_;
++ match_glyph_data = NULL,
++ matcher.set_match_func (NULL, NULL);
+ matcher.set_lookup_props (c->lookup_props);
+ /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+ matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+ /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
+ matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+- if (!context_match)
+- matcher.set_mask (c->lookup_mask);
+- matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
++ matcher.set_mask (context_match ? -1 : c->lookup_mask);
+ }
+- inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
+- inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
+- inline void set_match_func (matcher_t::match_func_t match_func,
+- const void *match_data,
++ inline void set_lookup_props (unsigned int lookup_props)
++ {
++ matcher.set_lookup_props (lookup_props);
++ }
++ inline void set_match_func (matcher_t::match_func_t match_func_,
++ const void *match_data_,
+ const USHORT glyph_data[])
+ {
+- matcher.set_match_func (match_func, match_data);
++ matcher.set_match_func (match_func_, match_data_);
+ match_glyph_data = glyph_data;
+ }
+
+- inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
++ inline void reset (unsigned int start_index_,
++ unsigned int num_items_)
++ {
++ idx = start_index_;
++ num_items = num_items_;
++ end = c->buffer->len;
++ matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
++ }
++
+ inline void reject (void) { num_items++; match_glyph_data--; }
++
+ inline bool next (void)
+ {
+ assert (num_items > 0);
+- while (!has_no_chance ())
++ while (idx + num_items < end)
+ {
+ idx++;
+ const hb_glyph_info_t &info = c->buffer->info[idx];
+@@ -450,53 +401,10 @@
+ }
+ return false;
+ }
+-
+- unsigned int idx;
+- protected:
+- hb_apply_context_t *c;
+- matcher_t matcher;
+- const USHORT *match_glyph_data;
+-
+- unsigned int num_items;
+- unsigned int end;
+- };
+-
+- struct skipping_backward_iterator_t
+- {
+- inline skipping_backward_iterator_t (hb_apply_context_t *c_,
+- unsigned int start_index_,
+- unsigned int num_items_,
+- bool context_match = false) :
+- idx (start_index_),
+- c (c_),
+- match_glyph_data (NULL),
+- num_items (num_items_)
+- {
+- matcher.set_lookup_props (c->lookup_props);
+- /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+- matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+- /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
+- matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+- if (!context_match)
+- matcher.set_mask (c->lookup_mask);
+- matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+- }
+- inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
+- inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
+- inline void set_match_func (matcher_t::match_func_t match_func,
+- const void *match_data,
+- const USHORT glyph_data[])
+- {
+- matcher.set_match_func (match_func, match_data);
+- match_glyph_data = glyph_data;
+- }
+-
+- inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
+- inline void reject (void) { num_items++; }
+ inline bool prev (void)
+ {
+ assert (num_items > 0);
+- while (!has_no_chance ())
++ while (idx >= num_items)
+ {
+ idx--;
+ const hb_glyph_info_t &info = c->buffer->out_info[idx];
+@@ -528,44 +436,109 @@
+ const USHORT *match_glyph_data;
+
+ unsigned int num_items;
++ unsigned int end;
+ };
+
++
++ inline const char *get_name (void) { return "APPLY"; }
++ typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
++ template <typename T>
++ inline return_t dispatch (const T &obj) { return obj.apply (this); }
++ static return_t default_return_value (void) { return false; }
++ bool stop_sublookup_iteration (return_t r) const { return r; }
++ return_t recurse (unsigned int lookup_index)
++ {
++ if (unlikely (nesting_level_left == 0 || !recurse_func))
++ return default_return_value ();
++
++ nesting_level_left--;
++ bool ret = recurse_func (this, lookup_index);
++ nesting_level_left++;
++ return ret;
++ }
++
++ unsigned int table_index; /* GSUB/GPOS */
++ hb_font_t *font;
++ hb_face_t *face;
++ hb_buffer_t *buffer;
++ hb_direction_t direction;
++ hb_mask_t lookup_mask;
++ bool auto_zwj;
++ recurse_func_t recurse_func;
++ unsigned int nesting_level_left;
++ unsigned int lookup_props;
++ const GDEF &gdef;
++ bool has_glyph_classes;
++ skipping_iterator_t iter_input, iter_context;
++ unsigned int lookup_index;
++ unsigned int debug_depth;
++
++
++ hb_apply_context_t (unsigned int table_index_,
++ hb_font_t *font_,
++ hb_buffer_t *buffer_) :
++ table_index (table_index_),
++ font (font_), face (font->face), buffer (buffer_),
++ direction (buffer_->props.direction),
++ lookup_mask (1),
++ auto_zwj (true),
++ recurse_func (NULL),
++ nesting_level_left (HB_MAX_NESTING_LEVEL),
++ lookup_props (0),
++ gdef (*hb_ot_layout_from_face (face)->gdef),
++ has_glyph_classes (gdef.has_glyph_classes ()),
++ iter_input (),
++ iter_context (),
++ lookup_index ((unsigned int) -1),
++ debug_depth (0) {}
++
++ inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
++ inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
++ inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
++ inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
++ inline void set_lookup_props (unsigned int lookup_props_)
++ {
++ lookup_props = lookup_props_;
++ iter_input.init (this, false);
++ iter_context.init (this, true);
++ }
++
+ inline bool
+ match_properties_mark (hb_codepoint_t glyph,
+ unsigned int glyph_props,
+- unsigned int lookup_props) const
++ unsigned int match_props) const
+ {
+ /* If using mark filtering sets, the high short of
+- * lookup_props has the set index.
++ * match_props has the set index.
+ */
+- if (lookup_props & LookupFlag::UseMarkFilteringSet)
+- return gdef.mark_set_covers (lookup_props >> 16, glyph);
++ if (match_props & LookupFlag::UseMarkFilteringSet)
++ return gdef.mark_set_covers (match_props >> 16, glyph);
+
+- /* The second byte of lookup_props has the meaning
++ /* The second byte of match_props has the meaning
+ * "ignore marks of attachment type different than
+ * the attachment type specified."
+ */
+- if (lookup_props & LookupFlag::MarkAttachmentType)
+- return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
++ if (match_props & LookupFlag::MarkAttachmentType)
++ return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
+
+ return true;
+ }
+
+ inline bool
+ check_glyph_property (const hb_glyph_info_t *info,
+- unsigned int lookup_props) const
++ unsigned int match_props) const
+ {
+ hb_codepoint_t glyph = info->codepoint;
+ unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
+
+ /* Not covered, if, for example, glyph class is ligature and
+- * lookup_props includes LookupFlags::IgnoreLigatures
++ * match_props includes LookupFlags::IgnoreLigatures
+ */
+- if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
++ if (glyph_props & match_props & LookupFlag::IgnoreFlags)
+ return false;
+
+ if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
+- return match_properties_mark (glyph, glyph_props, lookup_props);
++ return match_properties_mark (glyph, glyph_props, match_props);
+
+ return true;
+ }
+@@ -731,19 +704,19 @@
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *end_offset,
+- unsigned int match_positions[MAX_CONTEXT_LENGTH],
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+ bool *p_is_mark_ligature = NULL,
+ unsigned int *p_total_component_count = NULL)
+ {
+ TRACE_APPLY (NULL);
+
+- if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
++ if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
+
+ hb_buffer_t *buffer = c->buffer;
+
+- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
++ skippy_iter.reset (buffer->idx, count - 1);
+ skippy_iter.set_match_func (match_func, match_data, input);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+
+ /*
+ * This is perhaps the trickiest part of OpenType... Remarks:
+@@ -774,7 +747,7 @@
+ match_positions[0] = buffer->idx;
+ for (unsigned int i = 1; i < count; i++)
+ {
+- if (!skippy_iter.next ()) return TRACE_RETURN (false);
++ if (!skippy_iter.next ()) return_trace (false);
+
+ match_positions[i] = skippy_iter.idx;
+
+@@ -786,13 +759,13 @@
+ * all subsequent components should be attached to the same ligature
+ * component, otherwise we shouldn't ligate them. */
+ if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
+- return TRACE_RETURN (false);
++ return_trace (false);
+ } else {
+ /* If first component was NOT attached to a previous ligature component,
+ * all subsequent components should also NOT be attached to any ligature
+ * component, unless they are attached to the first component itself! */
+ if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
+@@ -807,11 +780,11 @@
+ if (p_total_component_count)
+ *p_total_component_count = total_component_count;
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+-static inline void ligate_input (hb_apply_context_t *c,
++static inline bool ligate_input (hb_apply_context_t *c,
+ unsigned int count, /* Including the first glyph */
+- unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int match_length,
+ hb_codepoint_t lig_glyph,
+ bool is_mark_ligature,
+@@ -863,19 +836,21 @@
+ if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+ {
+ _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+- _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
+ }
+ }
+ c->replace_glyph_with_ligature (lig_glyph, klass);
+
+ for (unsigned int i = 1; i < count; i++)
+ {
+- while (buffer->idx < match_positions[i])
++ while (buffer->idx < match_positions[i] && !buffer->in_error)
+ {
+ if (!is_mark_ligature) {
++ unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
++ if (this_comp == 0)
++ this_comp = last_num_components;
+ unsigned int new_lig_comp = components_so_far - last_num_components +
+- MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
+- _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
++ MIN (this_comp, last_num_components);
++ _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+ }
+ buffer->next_glyph ();
+ }
+@@ -892,14 +867,17 @@
+ /* Re-adjust components for any marks following. */
+ for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+ if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
++ unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
++ if (!this_comp)
++ break;
+ unsigned int new_lig_comp = components_so_far - last_num_components +
+- MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
++ MIN (this_comp, last_num_components);
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
+ } else
+ break;
+ }
+ }
+- TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ static inline bool match_backtrack (hb_apply_context_t *c,
+@@ -910,15 +888,15 @@
+ {
+ TRACE_APPLY (NULL);
+
+- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
++ skippy_iter.reset (c->buffer->backtrack_len (), count);
+ skippy_iter.set_match_func (match_func, match_data, backtrack);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+
+ for (unsigned int i = 0; i < count; i++)
+ if (!skippy_iter.prev ())
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ static inline bool match_lookahead (hb_apply_context_t *c,
+@@ -930,24 +908,25 @@
+ {
+ TRACE_APPLY (NULL);
+
+- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
++ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
++ skippy_iter.reset (c->buffer->idx + offset - 1, count);
+ skippy_iter.set_match_func (match_func, match_data, lookahead);
+- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+
+ for (unsigned int i = 0; i < count; i++)
+ if (!skippy_iter.next ())
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+
+
+ struct LookupRecord
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this));
+ }
+
+ USHORT sequenceIndex; /* Index into current glyph
+@@ -970,7 +949,7 @@
+
+ static inline bool apply_lookup (hb_apply_context_t *c,
+ unsigned int count, /* Including the first glyph */
+- unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
+ unsigned int match_length)
+@@ -998,6 +977,11 @@
+ if (idx >= count)
+ continue;
+
++ /* Don't recurse to ourself at same position.
++ * Note that this test is too naive, it doesn't catch longer loops. */
++ if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
++ continue;
++
+ buffer->move_to (match_positions[idx]);
+
+ unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+@@ -1015,13 +999,13 @@
+ /* end can't go back past the current match position.
+ * Note: this is only true because we do NOT allow MultipleSubst
+ * with zero sequence len. */
+- end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
++ end = MAX (MIN((int) match_positions[idx] + 1, (int) new_len), int (end) + delta);
+
+ unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
+
+ if (delta > 0)
+ {
+- if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
++ if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
+ break;
+ }
+ else
+@@ -1048,7 +1032,7 @@
+
+ buffer->move_to (end);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+
+@@ -1120,7 +1104,7 @@
+ ContextApplyLookupContext &lookup_context)
+ {
+ unsigned int match_length = 0;
+- unsigned int match_positions[MAX_CONTEXT_LENGTH];
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+ return match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data,
+@@ -1157,18 +1141,19 @@
+ {
+ TRACE_WOULD_APPLY (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+- return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
++ return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+ }
+
+ inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+ {
+ TRACE_APPLY (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+- return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
++ return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+ }
+
+ public:
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ return inputCount.sanitize (c)
+ && lookupCount.sanitize (c)
+@@ -1215,9 +1200,9 @@
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ if ((this+rule[i]).would_apply (c, lookup_context))
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+@@ -1227,14 +1212,15 @@
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ if ((this+rule[i]).apply (c, lookup_context))
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (rule.sanitize (c, this));
++ return_trace (rule.sanitize (c, this));
+ }
+
+ protected:
+@@ -1291,7 +1277,7 @@
+ {match_glyph},
+ NULL
+ };
+- return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
++ return_trace (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -1304,19 +1290,20 @@
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+ if (likely (index == NOT_COVERED))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ const RuleSet &rule_set = this+ruleSet[index];
+ struct ContextApplyLookupContext lookup_context = {
+ {match_glyph},
+ NULL
+ };
+- return TRACE_RETURN (rule_set.apply (c, lookup_context));
++ return_trace (rule_set.apply (c, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -1382,7 +1369,7 @@
+ {match_class},
+ &class_def
+ };
+- return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
++ return_trace (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -1394,7 +1381,7 @@
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const ClassDef &class_def = this+classDef;
+ index = class_def.get_class (c->buffer->cur().codepoint);
+@@ -1403,12 +1390,13 @@
+ {match_class},
+ &class_def
+ };
+- return TRACE_RETURN (rule_set.apply (c, lookup_context));
++ return_trace (rule_set.apply (c, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -1472,7 +1460,7 @@
+ {match_coverage},
+ this
+ };
+- return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
++ return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -1484,26 +1472,27 @@
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ struct ContextApplyLookupContext lookup_context = {
+ {match_coverage},
+ this
+ };
+- return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
++ return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!c->check_struct (this)) return TRACE_RETURN (false);
++ if (!c->check_struct (this)) return_trace (false);
+ unsigned int count = glyphCount;
+- if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
+- if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
++ if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
++ if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
+ for (unsigned int i = 0; i < count; i++)
+- if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
+- LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
+- return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
++ if (!coverageZ[i].sanitize (c, this)) return_trace (false);
++ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
++ return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
+ }
+
+ protected:
+@@ -1526,22 +1515,12 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- case 2: return TRACE_RETURN (c->dispatch (u.format2));
+- case 3: return TRACE_RETURN (c->dispatch (u.format3));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- case 3: return TRACE_RETURN (u.format3.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ case 2: return_trace (c->dispatch (u.format2));
++ case 3: return_trace (c->dispatch (u.format3));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1652,7 +1631,7 @@
+ ChainContextApplyLookupContext &lookup_context)
+ {
+ unsigned int match_length = 0;
+- unsigned int match_positions[MAX_CONTEXT_LENGTH];
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+ return match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data[1],
+@@ -1706,11 +1685,11 @@
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+- return TRACE_RETURN (chain_context_would_apply_lookup (c,
+- backtrack.len, backtrack.array,
+- input.len, input.array,
+- lookahead.len, lookahead.array, lookup.len,
+- lookup.array, lookup_context));
++ return_trace (chain_context_would_apply_lookup (c,
++ backtrack.len, backtrack.array,
++ input.len, input.array,
++ lookahead.len, lookahead.array, lookup.len,
++ lookup.array, lookup_context));
+ }
+
+ inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+@@ -1719,22 +1698,23 @@
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+- return TRACE_RETURN (chain_context_apply_lookup (c,
+- backtrack.len, backtrack.array,
+- input.len, input.array,
+- lookahead.len, lookahead.array, lookup.len,
+- lookup.array, lookup_context));
++ return_trace (chain_context_apply_lookup (c,
++ backtrack.len, backtrack.array,
++ input.len, input.array,
++ lookahead.len, lookahead.array, lookup.len,
++ lookup.array, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
+- HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+- if (!input.sanitize (c)) return TRACE_RETURN (false);
+- ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+- if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
+- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+- return TRACE_RETURN (lookup.sanitize (c));
++ if (!backtrack.sanitize (c)) return_trace (false);
++ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
++ if (!input.sanitize (c)) return_trace (false);
++ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
++ if (!lookahead.sanitize (c)) return_trace (false);
++ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
++ return_trace (lookup.sanitize (c));
+ }
+
+ protected:
+@@ -1779,9 +1759,9 @@
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ if ((this+rule[i]).would_apply (c, lookup_context))
+- return TRACE_RETURN (true);
++ return_trace (true);
+
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+@@ -1790,14 +1770,15 @@
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ if ((this+rule[i]).apply (c, lookup_context))
+- return TRACE_RETURN (true);
++ return_trace (true);
+
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (rule.sanitize (c, this));
++ return_trace (rule.sanitize (c, this));
+ }
+
+ protected:
+@@ -1852,7 +1833,7 @@
+ {match_glyph},
+ {NULL, NULL, NULL}
+ };
+- return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
++ return_trace (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -1864,19 +1845,20 @@
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const ChainRuleSet &rule_set = this+ruleSet[index];
+ struct ChainContextApplyLookupContext lookup_context = {
+ {match_glyph},
+ {NULL, NULL, NULL}
+ };
+- return TRACE_RETURN (rule_set.apply (c, lookup_context));
++ return_trace (rule_set.apply (c, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -1955,7 +1937,7 @@
+ &input_class_def,
+ &lookahead_class_def}
+ };
+- return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
++ return_trace (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -1967,7 +1949,7 @@
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+@@ -1981,14 +1963,17 @@
+ &input_class_def,
+ &lookahead_class_def}
+ };
+- return TRACE_RETURN (rule_set.apply (c, lookup_context));
++ return_trace (rule_set.apply (c, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
+- inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
+- ruleSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) &&
++ backtrackClassDef.sanitize (c, this) &&
++ inputClassDef.sanitize (c, this) &&
++ lookaheadClassDef.sanitize (c, this) &&
++ ruleSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -2071,11 +2056,11 @@
+ {match_coverage},
+ {this, this, this}
+ };
+- return TRACE_RETURN (chain_context_would_apply_lookup (c,
+- backtrack.len, (const USHORT *) backtrack.array,
+- input.len, (const USHORT *) input.array + 1,
+- lookahead.len, (const USHORT *) lookahead.array,
+- lookup.len, lookup.array, lookup_context));
++ return_trace (chain_context_would_apply_lookup (c,
++ backtrack.len, (const USHORT *) backtrack.array,
++ input.len, (const USHORT *) input.array + 1,
++ lookahead.len, (const USHORT *) lookahead.array,
++ lookup.len, lookup.array, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+@@ -2090,7 +2075,7 @@
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+ unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+@@ -2098,23 +2083,24 @@
+ {match_coverage},
+ {this, this, this}
+ };
+- return TRACE_RETURN (chain_context_apply_lookup (c,
+- backtrack.len, (const USHORT *) backtrack.array,
+- input.len, (const USHORT *) input.array + 1,
+- lookahead.len, (const USHORT *) lookahead.array,
+- lookup.len, lookup.array, lookup_context));
++ return_trace (chain_context_apply_lookup (c,
++ backtrack.len, (const USHORT *) backtrack.array,
++ input.len, (const USHORT *) input.array + 1,
++ lookahead.len, (const USHORT *) lookahead.array,
++ lookup.len, lookup.array, lookup_context));
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
+- OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+- if (!input.sanitize (c, this)) return TRACE_RETURN (false);
+- if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
+- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+- if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
+- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+- return TRACE_RETURN (lookup.sanitize (c));
++ if (!backtrack.sanitize (c, this)) return_trace (false);
++ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
++ if (!input.sanitize (c, this)) return_trace (false);
++ if (!input.len) return_trace (false); /* To be consistent with Context. */
++ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
++ if (!lookahead.sanitize (c, this)) return_trace (false);
++ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
++ return_trace (lookup.sanitize (c));
+ }
+
+ protected:
+@@ -2144,22 +2130,12 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- case 2: return TRACE_RETURN (c->dispatch (u.format2));
+- case 3: return TRACE_RETURN (c->dispatch (u.format3));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- case 3: return TRACE_RETURN (u.format3.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ case 2: return_trace (c->dispatch (u.format2));
++ case 3: return_trace (c->dispatch (u.format3));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -2173,14 +2149,32 @@
+ };
+
+
++template <typename T>
+ struct ExtensionFormat1
+ {
+ inline unsigned int get_type (void) const { return extensionLookupType; }
+- inline unsigned int get_offset (void) const { return extensionOffset; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ template <typename X>
++ inline const X& get_subtable (void) const
++ {
++ unsigned int offset = extensionOffset;
++ if (unlikely (!offset)) return Null(typename T::LookupSubTable);
++ return StructAtOffset<typename T::LookupSubTable> (this, offset);
++ }
++
++ template <typename context_t>
++ inline typename context_t::return_t dispatch (context_t *c) const
++ {
++ TRACE_DISPATCH (this, format);
++ if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
++ return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
++ }
++
++ /* This is called from may_dispatch() above with hb_sanitize_context_t. */
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this));
++ return_trace (c->check_struct (this) && extensionOffset != 0);
+ }
+
+ protected:
+@@ -2204,49 +2198,30 @@
+ default:return 0;
+ }
+ }
+- inline unsigned int get_offset (void) const
+- {
+- switch (u.format) {
+- case 1: return u.format1.get_offset ();
+- default:return 0;
+- }
+- }
+-
+ template <typename X>
+ inline const X& get_subtable (void) const
+ {
+- unsigned int offset = get_offset ();
+- if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+- return StructAtOffset<typename T::LookupSubTable> (this, offset);
++ switch (u.format) {
++ case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
++ default:return Null(typename T::LookupSubTable);
++ }
+ }
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+- return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
+- }
+-
+- inline bool sanitize_self (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
++ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (u.format1.dispatch (c));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!sanitize_self (c)) return TRACE_RETURN (false);
+- unsigned int offset = get_offset ();
+- if (unlikely (!offset)) return TRACE_RETURN (true);
+- return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
+- }
+-
+ protected:
+ union {
+ USHORT format; /* Format identifier */
+- ExtensionFormat1 format1;
++ ExtensionFormat1<T> format1;
+ } u;
+ };
+
+@@ -2291,12 +2266,14 @@
+ inline const Lookup& get_lookup (unsigned int i) const
+ { return (this+lookupList)[i]; }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
+- scriptList.sanitize (c, this) &&
+- featureList.sanitize (c, this) &&
+- lookupList.sanitize (c, this));
++ return_trace (version.sanitize (c) &&
++ likely (version.major == 1) &&
++ scriptList.sanitize (c, this) &&
++ featureList.sanitize (c, this) &&
++ lookupList.sanitize (c, this));
+ }
+
+ protected:
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-gsub-table.hh gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-gsub-table.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh 2016-06-05 23:49:25.602988064 +0200
+@@ -67,7 +67,7 @@
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+- return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
++ return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -75,14 +75,14 @@
+ TRACE_APPLY (this);
+ hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ /* According to the Adobe Annotated OpenType Suite, result is always
+ * limited to 16bit. */
+ glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
+ c->replace_glyph (glyph_id);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -91,15 +91,16 @@
+ int delta)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
+ deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
++ return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+ }
+
+ protected:
+@@ -143,7 +144,7 @@
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+- return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
++ return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -151,14 +152,14 @@
+ TRACE_APPLY (this);
+ hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+- if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
++ if (unlikely (index >= substitute.len)) return_trace (false);
+
+ glyph_id = substitute[index];
+ c->replace_glyph (glyph_id);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -167,15 +168,16 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
+- if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
++ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
++ return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
+ }
+
+ protected:
+@@ -198,7 +200,7 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 2;
+ int delta = 0;
+ if (num_glyphs) {
+@@ -213,9 +215,9 @@
+ }
+ u.format.set (format);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
+- case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
+- default:return TRACE_RETURN (false);
++ case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
++ case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
++ default:return_trace (false);
+ }
+ }
+
+@@ -223,20 +225,11 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- case 2: return TRACE_RETURN (c->dispatch (u.format2));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- case 2: return TRACE_RETURN (u.format2.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ case 2: return_trace (c->dispatch (u.format2));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -280,14 +273,14 @@
+ * buffer->move_to() makes assumptions about this too. Perhaps fix
+ * in the future after figuring out what to do with the clusters.
+ */
+- if (unlikely (!count)) return TRACE_RETURN (false);
++ if (unlikely (!count)) return_trace (false);
+
+ /* Special-case to make it in-place and not consider this
+ * as a "multiplied" substitution. */
+ if (unlikely (count == 1))
+ {
+ c->replace_glyph (substitute.array[0]);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+@@ -299,7 +292,7 @@
+ }
+ c->buffer->skip_glyph ();
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -307,14 +300,15 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (substitute.sanitize (c));
++ return_trace (substitute.sanitize (c));
+ }
+
+ protected:
+@@ -353,7 +347,7 @@
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+- return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
++ return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -361,9 +355,9 @@
+ TRACE_APPLY (this);
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+- return TRACE_RETURN ((this+sequence[index]).apply (c));
++ return_trace ((this+sequence[index]).apply (c));
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -373,20 +367,21 @@
+ Supplier<GlyphID> &substitute_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ if (unlikely (!sequence[i].serialize (c, this).serialize (c,
+ substitute_glyphs_list,
+- substitute_len_list[i]))) return TRACE_RETURN (false);
++ substitute_len_list[i]))) return_trace (false);
+ substitute_len_list.advance (num_glyphs);
+- if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
+ }
+
+ protected:
+@@ -410,12 +405,12 @@
+ Supplier<GlyphID> &substitute_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format.set (format);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
+- default:return TRACE_RETURN (false);
++ case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
++ default:return_trace (false);
+ }
+ }
+
+@@ -423,18 +418,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -486,7 +473,7 @@
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+- return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
++ return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -495,11 +482,11 @@
+ hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const AlternateSet &alt_set = this+alternateSet[index];
+
+- if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
++ if (unlikely (!alt_set.len)) return_trace (false);
+
+ hb_mask_t glyph_mask = c->buffer->cur().mask;
+ hb_mask_t lookup_mask = c->lookup_mask;
+@@ -508,13 +495,13 @@
+ unsigned int shift = _hb_ctz (lookup_mask);
+ unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+- if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
++ if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
+
+ glyph_id = alt_set[alt_index - 1];
+
+ c->replace_glyph (glyph_id);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -524,20 +511,21 @@
+ Supplier<GlyphID> &alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
+ alternate_glyphs_list,
+- alternate_len_list[i]))) return TRACE_RETURN (false);
++ alternate_len_list[i]))) return_trace (false);
+ alternate_len_list.advance (num_glyphs);
+- if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -561,12 +549,12 @@
+ Supplier<GlyphID> &alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format.set (format);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
+- default:return TRACE_RETURN (false);
++ case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
++ default:return_trace (false);
+ }
+ }
+
+@@ -574,18 +562,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -622,13 +602,13 @@
+ {
+ TRACE_WOULD_APPLY (this);
+ if (c->len != component.len)
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ for (unsigned int i = 1; i < c->len; i++)
+ if (likely (c->glyphs[i] != component[i]))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -636,21 +616,21 @@
+ TRACE_APPLY (this);
+ unsigned int count = component.len;
+
+- if (unlikely (!count)) return TRACE_RETURN (false);
++ if (unlikely (!count)) return_trace (false);
+
+ /* Special-case to make it in-place and not consider this
+ * as a "ligated" substitution. */
+ if (unlikely (count == 1))
+ {
+ c->replace_glyph (ligGlyph);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ bool is_mark_ligature = false;
+ unsigned int total_component_count = 0;
+
+ unsigned int match_length = 0;
+- unsigned int match_positions[MAX_CONTEXT_LENGTH];
++ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
+
+ if (likely (!match_input (c, count,
+ &component[1],
+@@ -660,7 +640,7 @@
+ match_positions,
+ &is_mark_ligature,
+ &total_component_count)))
+- return TRACE_RETURN (false);
++ return_trace (false);
+
+ ligate_input (c,
+ count,
+@@ -670,7 +650,7 @@
+ is_mark_ligature,
+ total_component_count);
+
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -679,16 +659,17 @@
+ unsigned int num_components /* Including first component */)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
+ ligGlyph = ligature;
+- if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
++ return_trace (true);
+ }
+
+ public:
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
++ return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
+ }
+
+ protected:
+@@ -727,9 +708,9 @@
+ {
+ const Ligature &lig = this+ligature[i];
+ if (lig.would_apply (c))
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -739,10 +720,10 @@
+ for (unsigned int i = 0; i < num_ligs; i++)
+ {
+ const Ligature &lig = this+ligature[i];
+- if (lig.apply (c)) return TRACE_RETURN (true);
++ if (lig.apply (c)) return_trace (true);
+ }
+
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -752,21 +733,22 @@
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
+ for (unsigned int i = 0; i < num_ligatures; i++)
+ if (unlikely (!ligature[i].serialize (c, this).serialize (c,
+ ligatures[i],
+ component_list,
+- component_count_list[i]))) return TRACE_RETURN (false);
++ component_count_list[i]))) return_trace (false);
+ ligatures.advance (num_ligatures);
+ component_count_list.advance (num_ligatures);
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (ligature.sanitize (c, this));
++ return_trace (ligature.sanitize (c, this));
+ }
+
+ protected:
+@@ -808,10 +790,10 @@
+ {
+ TRACE_WOULD_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const LigatureSet &lig_set = this+ligatureSet[index];
+- return TRACE_RETURN (lig_set.would_apply (c));
++ return_trace (lig_set.would_apply (c));
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+@@ -820,10 +802,10 @@
+ hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
+
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const LigatureSet &lig_set = this+ligatureSet[index];
+- return TRACE_RETURN (lig_set.apply (c));
++ return_trace (lig_set.apply (c));
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+@@ -835,22 +817,23 @@
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+- if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (*this))) return_trace (false);
++ if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
+ for (unsigned int i = 0; i < num_first_glyphs; i++)
+ if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
+ ligatures_list,
+ component_count_list,
+ ligature_per_first_glyph_count_list[i],
+- component_list))) return TRACE_RETURN (false);
++ component_list))) return_trace (false);
+ ligature_per_first_glyph_count_list.advance (num_first_glyphs);
+- if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
++ return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
+ }
+
+ protected:
+@@ -876,13 +859,18 @@
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
++ if (unlikely (!c->extend_min (u.format))) return_trace (false);
+ unsigned int format = 1;
+ u.format.set (format);
+ switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+- ligatures_list, component_count_list, component_list));
+- default:return TRACE_RETURN (false);
++ case 1: return_trace (u.format1.serialize (c,
++ first_glyphs,
++ ligature_per_first_glyph_count_list,
++ num_first_glyphs,
++ ligatures_list,
++ component_count_list,
++ component_list));
++ default:return_trace (false);
+ }
+ }
+
+@@ -890,18 +878,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -984,17 +964,17 @@
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+- return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
++ return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+- if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
+- return TRACE_RETURN (false); /* No chaining to this type */
++ if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
++ return_trace (false); /* No chaining to this type */
+
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
+- if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
++ if (likely (index == NOT_COVERED)) return_trace (false);
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+@@ -1011,21 +991,22 @@
+ /* Note: We DON'T decrease buffer->idx. The main loop does it
+ * for us. This is useful for preventing surprises if someone
+ * calls us through a Context lookup. */
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+ if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
+- return TRACE_RETURN (false);
+- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
++ return_trace (false);
++ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ if (!lookahead.sanitize (c, this))
+- return TRACE_RETURN (false);
+- ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+- return TRACE_RETURN (substitute.sanitize (c));
++ return_trace (false);
++ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
++ return_trace (substitute.sanitize (c));
+ }
+
+ protected:
+@@ -1054,18 +1035,10 @@
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
++ if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+ switch (u.format) {
+- case 1: return TRACE_RETURN (c->dispatch (u.format1));
+- default:return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c) {
+- TRACE_SANITIZE (this);
+- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+- switch (u.format) {
+- case 1: return TRACE_RETURN (u.format1.sanitize (c));
+- default:return TRACE_RETURN (true);
++ case 1: return_trace (c->dispatch (u.format1));
++ default:return_trace (c->default_return_value ());
+ }
+ }
+
+@@ -1101,41 +1074,23 @@
+ inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
+ {
+ TRACE_DISPATCH (this, lookup_type);
++ if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
+ switch (lookup_type) {
+- case Single: return TRACE_RETURN (u.single.dispatch (c));
+- case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
+- case Alternate: return TRACE_RETURN (u.alternate.dispatch (c));
+- case Ligature: return TRACE_RETURN (u.ligature.dispatch (c));
+- case Context: return TRACE_RETURN (u.context.dispatch (c));
+- case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
+- case Extension: return TRACE_RETURN (u.extension.dispatch (c));
+- case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
+- default: return TRACE_RETURN (c->default_return_value ());
+- }
+- }
+-
+- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
+- TRACE_SANITIZE (this);
+- if (!u.header.sub_format.sanitize (c))
+- return TRACE_RETURN (false);
+- switch (lookup_type) {
+- case Single: return TRACE_RETURN (u.single.sanitize (c));
+- case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
+- case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
+- case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
+- case Context: return TRACE_RETURN (u.context.sanitize (c));
+- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
+- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
+- case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
+- default: return TRACE_RETURN (true);
++ case Single: return_trace (u.single.dispatch (c));
++ case Multiple: return_trace (u.multiple.dispatch (c));
++ case Alternate: return_trace (u.alternate.dispatch (c));
++ case Ligature: return_trace (u.ligature.dispatch (c));
++ case Context: return_trace (u.context.dispatch (c));
++ case ChainContext: return_trace (u.chainContext.dispatch (c));
++ case Extension: return_trace (u.extension.dispatch (c));
++ case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
++ default: return_trace (c->default_return_value ());
+ }
+ }
+
+ protected:
+ union {
+- struct {
+- USHORT sub_format;
+- } header;
++ USHORT sub_format;
+ SingleSubst single;
+ MultipleSubst multiple;
+ AlternateSubst alternate;
+@@ -1146,14 +1101,14 @@
+ ReverseChainSingleSubst reverseChainContextSingle;
+ } u;
+ public:
+- DEFINE_SIZE_UNION (2, header.sub_format);
++ DEFINE_SIZE_UNION (2, sub_format);
+ };
+
+
+ struct SubstLookup : Lookup
+ {
+ inline const SubstLookupSubTable& get_subtable (unsigned int i) const
+- { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
++ { return Lookup::get_subtable<SubstLookupSubTable> (i); }
+
+ inline static bool lookup_type_is_reverse (unsigned int lookup_type)
+ { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
+@@ -1166,56 +1121,47 @@
+ return lookup_type_is_reverse (type);
+ }
+
++ inline bool apply (hb_apply_context_t *c) const
++ {
++ TRACE_APPLY (this);
++ return_trace (dispatch (c));
++ }
++
+ inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
+ {
+ TRACE_CLOSURE (this);
+ c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
+- return TRACE_RETURN (dispatch (c));
++ return_trace (dispatch (c));
+ }
+
+ inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+- return TRACE_RETURN (dispatch (c));
++ return_trace (dispatch (c));
+ }
+
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const
+ {
+- hb_get_coverage_context_t c;
+- const Coverage *last = NULL;
+- unsigned int count = get_subtable_count ();
+- for (unsigned int i = 0; i < count; i++) {
+- const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
+- if (coverage != last) {
+- coverage->add_coverage (glyphs);
+- last = coverage;
+- }
+- }
++ hb_add_coverage_context_t<set_t> c (glyphs);
++ dispatch (&c);
+ }
+
+- inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
++ inline bool would_apply (hb_would_apply_context_t *c,
++ const hb_ot_layout_lookup_accelerator_t *accel) const
+ {
+ TRACE_WOULD_APPLY (this);
+- if (unlikely (!c->len)) return TRACE_RETURN (false);
+- if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false);
+- return TRACE_RETURN (dispatch (c));
+- }
+-
+- inline bool apply_once (hb_apply_context_t *c) const
+- {
+- TRACE_APPLY (this);
+- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
+- return TRACE_RETURN (false);
+- return TRACE_RETURN (dispatch (c));
++ if (unlikely (!c->len)) return_trace (false);
++ if (!accel->may_have (c->glyphs[0])) return_trace (false);
++ return_trace (dispatch (c));
+ }
+
+ static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+
+ inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
+ unsigned int i)
+- { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
++ { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
+
+ inline bool serialize_single (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+@@ -1224,8 +1170,8 @@
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
+- return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
++ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
++ return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
+ }
+
+ inline bool serialize_multiple (hb_serialize_context_t *c,
+@@ -1236,9 +1182,12 @@
+ Supplier<GlyphID> &substitute_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
+- return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
+- substitute_glyphs_list));
++ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
++ return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
++ glyphs,
++ substitute_len_list,
++ num_glyphs,
++ substitute_glyphs_list));
+ }
+
+ inline bool serialize_alternate (hb_serialize_context_t *c,
+@@ -1249,9 +1198,12 @@
+ Supplier<GlyphID> &alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
+- return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
+- alternate_glyphs_list));
++ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
++ return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
++ glyphs,
++ alternate_len_list,
++ num_glyphs,
++ alternate_glyphs_list));
+ }
+
+ inline bool serialize_ligature (hb_serialize_context_t *c,
+@@ -1264,9 +1216,14 @@
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
+- return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+- ligatures_list, component_count_list, component_list));
++ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
++ return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
++ first_glyphs,
++ ligature_per_first_glyph_count_list,
++ num_first_glyphs,
++ ligatures_list,
++ component_count_list,
++ component_list));
+ }
+
+ template <typename context_t>
+@@ -1274,24 +1231,13 @@
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+- {
+- unsigned int lookup_type = get_type ();
+- TRACE_DISPATCH (this, lookup_type);
+- unsigned int count = get_subtable_count ();
+- for (unsigned int i = 0; i < count; i++) {
+- typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
+- if (c->stop_sublookup_iteration (r))
+- return TRACE_RETURN (r);
+- }
+- return TRACE_RETURN (c->default_return_value ());
+- }
++ { return Lookup::dispatch<SubstLookupSubTable> (c); }
+
+- inline bool sanitize (hb_sanitize_context_t *c)
++ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
+- OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
+- if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
++ if (unlikely (!Lookup::sanitize (c))) return_trace (false);
++ if (unlikely (!dispatch (c))) return_trace (false);
+
+ if (unlikely (get_type () == SubstLookupSubTable::Extension))
+ {
+@@ -1302,9 +1248,9 @@
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 1; i < count; i++)
+ if (get_subtable (i).u.extension.get_type () != type)
+- return TRACE_RETURN (false);
++ return_trace (false);
+ }
+- return TRACE_RETURN (true);
++ return_trace (true);
+ }
+ };
+
+@@ -1324,11 +1270,12 @@
+ static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
+- OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+- return TRACE_RETURN (list.sanitize (c, this));
++ if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
++ const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
++ return_trace (list.sanitize (c, this));
+ }
+ public:
+ DEFINE_SIZE_STATIC (10);
+@@ -1362,7 +1309,7 @@
+ {
+ unsigned int type = get_type ();
+ if (unlikely (type == SubstLookupSubTable::Extension))
+- return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
++ return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
+ return SubstLookup::lookup_type_is_reverse (type);
+ }
+
+@@ -1379,9 +1326,12 @@
+ const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
+ const SubstLookup &l = gsub.get_lookup (lookup_index);
+ unsigned int saved_lookup_props = c->lookup_props;
+- c->set_lookup (l);
+- bool ret = l.apply_once (c);
+- c->lookup_props = saved_lookup_props;
++ unsigned int saved_lookup_index = c->lookup_index;
++ c->set_lookup_index (lookup_index);
++ c->set_lookup_props (l.get_props ());
++ bool ret = l.dispatch (c);
++ c->set_lookup_index (saved_lookup_index);
++ c->set_lookup_props (saved_lookup_props);
+ return ret;
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout.h gfx/harfbuzz/src/hb-ot-layout.h
+--- gfx/harfbuzz/src_old/hb-ot-layout.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout.h 2016-06-05 23:49:32.503951121 +0200
+@@ -48,7 +48,7 @@
+ * GDEF
+ */
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_has_glyph_classes (hb_face_t *face);
+
+ typedef enum {
+@@ -59,11 +59,11 @@
+ HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 4
+ } hb_ot_layout_glyph_class_t;
+
+-hb_ot_layout_glyph_class_t
++HB_EXTERN hb_ot_layout_glyph_class_t
+ hb_ot_layout_get_glyph_class (hb_face_t *face,
+ hb_codepoint_t glyph);
+
+-void
++HB_EXTERN void
+ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
+ hb_ot_layout_glyph_class_t klass,
+ hb_set_t *glyphs /* OUT */);
+@@ -71,7 +71,7 @@
+
+ /* Not that useful. Provides list of attach points for a glyph that a
+ * client may want to cache */
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_get_attach_points (hb_face_t *face,
+ hb_codepoint_t glyph,
+ unsigned int start_offset,
+@@ -79,7 +79,7 @@
+ unsigned int *point_array /* OUT */);
+
+ /* Ligature caret positions */
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_get_ligature_carets (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t glyph,
+@@ -96,35 +96,35 @@
+ #define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
+ #define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_table_get_script_tags (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int start_offset,
+ unsigned int *script_count /* IN/OUT */,
+ hb_tag_t *script_tags /* OUT */);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_table_find_script (hb_face_t *face,
+ hb_tag_t table_tag,
+ hb_tag_t script_tag,
+ unsigned int *script_index);
+
+ /* Like find_script, but takes zero-terminated array of scripts to test */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_table_choose_script (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *script_tags,
+ unsigned int *script_index,
+ hb_tag_t *chosen_script);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int start_offset,
+ unsigned int *feature_count /* IN/OUT */,
+ hb_tag_t *feature_tags /* OUT */);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_script_get_language_tags (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+@@ -132,21 +132,21 @@
+ unsigned int *language_count /* IN/OUT */,
+ hb_tag_t *language_tags /* OUT */);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_script_find_language (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ hb_tag_t language_tag,
+ unsigned int *language_index);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_language_get_required_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+@@ -154,7 +154,7 @@
+ unsigned int *feature_index,
+ hb_tag_t *feature_tag);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+@@ -163,7 +163,7 @@
+ unsigned int *feature_count /* IN/OUT */,
+ unsigned int *feature_indexes /* OUT */);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+@@ -172,7 +172,7 @@
+ unsigned int *feature_count /* IN/OUT */,
+ hb_tag_t *feature_tags /* OUT */);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_language_find_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+@@ -180,7 +180,7 @@
+ hb_tag_t feature_tag,
+ unsigned int *feature_index);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_feature_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+@@ -188,12 +188,12 @@
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_ot_layout_table_get_lookup_count (hb_face_t *face,
+ hb_tag_t table_tag);
+
+
+-void
++HB_EXTERN void
+ hb_ot_layout_collect_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *scripts,
+@@ -201,7 +201,7 @@
+ const hb_tag_t *features,
+ hb_set_t *lookup_indexes /* OUT */);
+
+-void
++HB_EXTERN void
+ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+@@ -228,7 +228,7 @@
+ const hb_ot_layout_glyph_sequence_t *sequence,
+ void *user_data);
+
+-void
++HB_EXTERN void
+ Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+@@ -241,17 +241,17 @@
+ * GSUB
+ */
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_has_substitution (hb_face_t *face);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_lookup_would_substitute (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context);
+
+-void
++HB_EXTERN void
+ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
+ unsigned int lookup_index,
+ hb_set_t *glyphs
+@@ -259,7 +259,7 @@
+
+ #ifdef HB_NOT_IMPLEMENTED
+ /* Note: You better have GDEF when using this API, or marks won't do much. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ Xhb_ot_layout_lookup_substitute (hb_font_t *font,
+ unsigned int lookup_index,
+ const hb_ot_layout_glyph_sequence_t *sequence,
+@@ -274,12 +274,12 @@
+ * GPOS
+ */
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_has_positioning (hb_face_t *face);
+
+ #ifdef HB_NOT_IMPLEMENTED
+ /* Note: You better have GDEF when using this API, or marks won't do much. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ Xhb_ot_layout_lookup_position (hb_font_t *font,
+ unsigned int lookup_index,
+ const hb_ot_layout_glyph_sequence_t *sequence,
+@@ -288,7 +288,7 @@
+
+ /* Optical 'size' feature info. Returns true if found.
+ * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_get_size_params (hb_face_t *face,
+ unsigned int *design_size, /* OUT. May be NULL */
+ unsigned int *subfamily_id, /* OUT. May be NULL */
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-jstf-table.hh gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-jstf-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-jstf-table.hh 2016-06-05 23:49:28.544972286 +0200
+@@ -54,19 +54,20 @@
+
+ struct JstfPriority
+ {
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- shrinkageEnableGSUB.sanitize (c, this) &&
+- shrinkageDisableGSUB.sanitize (c, this) &&
+- shrinkageEnableGPOS.sanitize (c, this) &&
+- shrinkageDisableGPOS.sanitize (c, this) &&
+- shrinkageJstfMax.sanitize (c, this) &&
+- extensionEnableGSUB.sanitize (c, this) &&
+- extensionDisableGSUB.sanitize (c, this) &&
+- extensionEnableGPOS.sanitize (c, this) &&
+- extensionDisableGPOS.sanitize (c, this) &&
+- extensionJstfMax.sanitize (c, this));
++ return_trace (c->check_struct (this) &&
++ shrinkageEnableGSUB.sanitize (c, this) &&
++ shrinkageDisableGSUB.sanitize (c, this) &&
++ shrinkageEnableGPOS.sanitize (c, this) &&
++ shrinkageDisableGPOS.sanitize (c, this) &&
++ shrinkageJstfMax.sanitize (c, this) &&
++ extensionEnableGSUB.sanitize (c, this) &&
++ extensionDisableGSUB.sanitize (c, this) &&
++ extensionEnableGPOS.sanitize (c, this) &&
++ extensionDisableGPOS.sanitize (c, this) &&
++ extensionJstfMax.sanitize (c, this));
+ }
+
+ protected:
+@@ -123,9 +124,10 @@
+ struct JstfLangSys : OffsetListOf<JstfPriority>
+ {
+ inline bool sanitize (hb_sanitize_context_t *c,
+- const Record<JstfLangSys>::sanitize_closure_t * = NULL) {
++ const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
++ return_trace (OffsetListOf<JstfPriority>::sanitize (c));
+ }
+ };
+
+@@ -163,11 +165,12 @@
+ inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+- const Record<JstfScript>::sanitize_closure_t * = NULL) {
++ const Record<JstfScript>::sanitize_closure_t * = NULL) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
+- defaultLangSys.sanitize (c, this) &&
+- langSys.sanitize (c, this));
++ return_trace (extenderGlyphs.sanitize (c, this) &&
++ defaultLangSys.sanitize (c, this) &&
++ langSys.sanitize (c, this));
+ }
+
+ protected:
+@@ -206,10 +209,12 @@
+ inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+ { return scriptList.find_index (tag, index); }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
+- scriptList.sanitize (c, this));
++ return_trace (version.sanitize (c) &&
++ likely (version.major == 1) &&
++ scriptList.sanitize (c, this));
+ }
+
+ protected:
+diff -uN gfx/harfbuzz/src_old/hb-ot-layout-private.hh gfx/harfbuzz/src/hb-ot-layout-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-layout-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-layout-private.hh 2016-06-05 23:49:29.952964753 +0200
+@@ -36,11 +36,20 @@
+ #include "hb-set-private.hh"
+
+
++/* Private API corresponding to hb-ot-layout.h: */
++
++HB_INTERNAL hb_bool_t
++hb_ot_layout_table_find_feature (hb_face_t *face,
++ hb_tag_t table_tag,
++ hb_tag_t feature_tag,
++ unsigned int *feature_index);
++
++
+ /*
+ * GDEF
+ */
+
+-typedef enum
++enum hb_ot_layout_glyph_props_flags_t
+ {
+ /* The following three match LookupFlags::Ignore* numbers. */
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
+@@ -55,7 +64,8 @@
+ HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+ HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
+-} hb_ot_layout_glyph_class_mask_t;
++};
++HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
+
+
+ /*
+@@ -126,11 +136,15 @@
+ lookup.add_coverage (&digest);
+ }
+
+- template <typename TLookup>
+- inline void fini (const TLookup &lookup HB_UNUSED)
++ inline void fini (void)
+ {
+ }
+
++ inline bool may_have (hb_codepoint_t g) const {
++ return digest.may_have (g);
++ }
++
++ private:
+ hb_set_digest_t digest;
+ };
+
+@@ -167,82 +181,182 @@
+ */
+
+ /* buffer var allocations, used during the entire shaping process */
+-#define unicode_props0() var2.u8[0]
+-#define unicode_props1() var2.u8[1]
++#define unicode_props() var2.u16[0]
+
+ /* buffer var allocations, used during the GSUB/GPOS processing */
+ #define glyph_props() var1.u16[0] /* GDEF glyph properties */
+ #define lig_props() var1.u8[2] /* GSUB/GPOS ligature tracking */
+ #define syllable() var1.u8[3] /* GSUB/GPOS shaping boundaries */
+
++
++/* loop over syllables */
++
++#define foreach_syllable(buffer, start, end) \
++ for (unsigned int \
++ _count = buffer->len, \
++ start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
++ start < _count; \
++ start = end, end = _next_syllable (buffer, start))
++
++static inline unsigned int
++_next_syllable (hb_buffer_t *buffer, unsigned int start)
++{
++ hb_glyph_info_t *info = buffer->info;
++ unsigned int count = buffer->len;
++
++ unsigned int syllable = info[start].syllable();
++ while (++start < count && syllable == info[start].syllable())
++ ;
++
++ return start;
++}
++
++
+ /* unicode_props */
+
+-enum {
+- MASK0_ZWJ = 0x20u,
+- MASK0_ZWNJ = 0x40u,
+- MASK0_IGNORABLE = 0x80u,
+- MASK0_GEN_CAT = 0x1Fu
++/* Design:
++ * unicode_props() is a two-byte number. The low byte includes:
++ * - General_Category: 5 bits.
++ * - A bit each for:
++ * * Is it Default_Ignorable(); we have a modified Default_Ignorable().
++ * * Is it U+200D ZWJ?
++ * * Is it U+200C ZWNJ?
++ *
++ * The high-byte has different meanings, switched by the Gen-Cat:
++ * - For Mn,Mc,Me: the modified Combining_Class.
++ * - For Ws: index of which space character this is, if space fallback
++ * is needed, ie. we don't set this by default, only if asked to.
++ *
++ * If needed, we can use the ZWJ/ZWNJ to use the high byte as well,
++ * freeing two more bits.
++ */
++
++enum hb_unicode_props_flags_t {
++ UPROPS_MASK_ZWJ = 0x20u,
++ UPROPS_MASK_ZWNJ = 0x40u,
++ UPROPS_MASK_IGNORABLE = 0x80u,
++ UPROPS_MASK_GEN_CAT = 0x1Fu
+ };
++HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
+
+ static inline void
+-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
++_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
+ {
+- /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
+- info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+- (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
+- (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
+- (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
+- info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
++ hb_unicode_funcs_t *unicode = buffer->unicode;
++ unsigned int u = info->codepoint;
++ unsigned int gen_cat = (unsigned int) unicode->general_category (u);
++ unsigned int props = gen_cat;
++
++ if (u >= 0x80)
++ {
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
++ if (unlikely (unicode->is_default_ignorable (u)))
++ {
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
++ props |= UPROPS_MASK_IGNORABLE;
++ if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
++ if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
++ }
++ else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK (gen_cat)))
++ {
++ /* Only Mn and Mc can have non-zero ccc:
++ * http://www.unicode.org/policies/stability_policy.html#Property_Value
++ * """
++ * Canonical_Combining_Class, General_Category
++ * All characters other than those with General_Category property values
++ * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
++ * property value 0.
++ * 1.1.5+
++ * """
++ *
++ * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
++ * the "else if".
++ */
++ props |= unicode->modified_combining_class (info->codepoint)<<8;
++ }
++ }
++
++ info->unicode_props() = props;
+ }
+
+ static inline void
+ _hb_glyph_info_set_general_category (hb_glyph_info_t *info,
+ hb_unicode_general_category_t gen_cat)
+ {
+- info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
++ /* Clears top-byte. */
++ info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
+ }
+
+ static inline hb_unicode_general_category_t
+ _hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+ {
+- return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
++ return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+ }
+
++static inline bool
++_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
++{
++ return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
++}
+ static inline void
+ _hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
+ unsigned int modified_class)
+ {
+- info->unicode_props1() = modified_class;
++ if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
++ return;
++ info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
+ }
+-
+ static inline unsigned int
+ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
+ {
+- return info->unicode_props1();
++ return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
++}
++
++static inline bool
++_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
++{
++ return _hb_glyph_info_get_general_category (info) ==
++ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
++}
++static inline void
++_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
++{
++ if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
++ return;
++ info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
++}
++static inline hb_unicode_funcs_t::space_t
++_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
++{
++ return _hb_glyph_info_is_unicode_space (info) ?
++ (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
++ hb_unicode_funcs_t::NOT_SPACE;
+ }
+
++static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
++
+ static inline hb_bool_t
+ _hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
+ {
+- return !!(info->unicode_props0() & MASK0_IGNORABLE);
++ return (info->unicode_props() & UPROPS_MASK_IGNORABLE) && !_hb_glyph_info_ligated (info);
+ }
+
+ static inline hb_bool_t
+ _hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+ {
+- return !!(info->unicode_props0() & MASK0_ZWNJ);
++ return !!(info->unicode_props() & UPROPS_MASK_ZWNJ);
+ }
+
+ static inline hb_bool_t
+ _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+ {
+- return !!(info->unicode_props0() & MASK0_ZWJ);
++ return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
+ }
+
+ static inline void
+ _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
+ {
+- info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
++ info->unicode_props() ^= UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ;
+ }
+
+ /* lig_props: aka lig_id / lig_comp
+@@ -402,28 +516,31 @@
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+ }
+
++static inline void
++_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
++{
++ info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
++}
++
+
+ /* Allocation / deallocation. */
+
+ static inline void
+ _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+ {
+- HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
+- HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
++ HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
+ }
+
+ static inline void
+ _hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
+ {
+- HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
+- HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
++ HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
+ }
+
+ static inline void
+ _hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
+ {
+- HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
+- HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
++ HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
+ }
+
+ static inline void
+diff -uN gfx/harfbuzz/src_old/hb-ot-map.cc gfx/harfbuzz/src/hb-ot-map.cc
+--- gfx/harfbuzz/src_old/hb-ot-map.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-map.cc 2016-06-05 23:49:34.955938050 +0200
+@@ -89,7 +89,7 @@
+
+ for (unsigned int table_index = 0; table_index < 2; table_index++) {
+ hb_tag_t table_tag = table_tags[table_index];
+- found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
++ found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+ hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+ }
+ }
+@@ -216,6 +216,16 @@
+ info->tag,
+ &feature_index[table_index]);
+ }
++ if (!found && (info->flags & F_GLOBAL_SEARCH))
++ {
++ for (unsigned int table_index = 0; table_index < 2; table_index++)
++ {
++ found |= hb_ot_layout_table_find_feature (face,
++ table_tags[table_index],
++ info->tag,
++ &feature_index[table_index]);
++ }
++ }
+ if (!found && !(info->flags & F_HAS_FALLBACK))
+ continue;
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-map-private.hh gfx/harfbuzz/src/hb-ot-map-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-map-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-map-private.hh 2016-06-05 23:49:33.714944647 +0200
+@@ -154,27 +154,14 @@
+
+ enum hb_ot_map_feature_flags_t {
+ F_NONE = 0x0000u,
+- F_GLOBAL = 0x0001u,
+- F_HAS_FALLBACK = 0x0002u,
+- F_MANUAL_ZWJ = 0x0004u
++ F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
++ F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
++ F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */
++ F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */
+ };
++HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
+ /* Macro version for where const is desired. */
+ #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+-static inline hb_ot_map_feature_flags_t
+-operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+-{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
+-static inline hb_ot_map_feature_flags_t
+-operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+-{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
+-static inline hb_ot_map_feature_flags_t
+-operator ~ (hb_ot_map_feature_flags_t r)
+-{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
+-static inline hb_ot_map_feature_flags_t&
+-operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
+-{ l = l | r; return l; }
+-static inline hb_ot_map_feature_flags_t&
+-operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
+-{ l = l & r; return l; }
+
+
+ struct hb_ot_map_builder_t
+@@ -216,7 +203,8 @@
+ unsigned int stage[2]; /* GSUB/GPOS */
+
+ static int cmp (const feature_info_t *a, const feature_info_t *b)
+- { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
++ { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) :
++ (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); }
+ };
+
+ struct stage_info_t {
+diff -uN gfx/harfbuzz/src_old/hb-ot-maxp-table.hh gfx/harfbuzz/src/hb-ot-maxp-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-maxp-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-maxp-table.hh 2016-06-05 23:49:36.145931692 +0200
+@@ -43,14 +43,17 @@
+ {
+ static const hb_tag_t tableTag = HB_OT_TAG_maxp;
+
+- inline unsigned int get_num_glyphs (void) const {
++ inline unsigned int get_num_glyphs (void) const
++ {
+ return numGlyphs;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
++ return_trace (c->check_struct (this) &&
++ likely (version.major == 1 ||
++ (version.major == 0 && version.minor == 0x5000u)));
+ }
+
+ /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
+diff -uN gfx/harfbuzz/src_old/hb-ot-name-table.hh gfx/harfbuzz/src/hb-ot-name-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-name-table.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-name-table.hh 2016-06-05 23:49:37.289925602 +0200
+@@ -56,10 +56,11 @@
+ return 0;
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
++ {
+ TRACE_SANITIZE (this);
+ /* We can check from base all the way up to the end of string... */
+- return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
++ return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
+ }
+
+ USHORT platformID; /* Platform ID. */
+@@ -101,21 +102,22 @@
+ inline unsigned int get_size (void) const
+ { return min_size + count * nameRecord[0].min_size; }
+
+- inline bool sanitize_records (hb_sanitize_context_t *c) {
++ inline bool sanitize_records (hb_sanitize_context_t *c) const {
+ TRACE_SANITIZE (this);
+ char *string_pool = (char *) this + stringOffset;
+ unsigned int _count = count;
+ for (unsigned int i = 0; i < _count; i++)
+- if (!nameRecord[i].sanitize (c, string_pool)) return TRACE_RETURN (false);
+- return TRACE_RETURN (true);
++ if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false);
++ return_trace (true);
+ }
+
+- inline bool sanitize (hb_sanitize_context_t *c) {
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
+ TRACE_SANITIZE (this);
+- return TRACE_RETURN (c->check_struct (this) &&
+- likely (format == 0 || format == 1) &&
+- c->check_array (nameRecord, nameRecord[0].static_size, count) &&
+- sanitize_records (c));
++ return_trace (c->check_struct (this) &&
++ likely (format == 0 || format == 1) &&
++ c->check_array (nameRecord, nameRecord[0].static_size, count) &&
++ sanitize_records (c));
+ }
+
+ /* We only implement format 0 for now. */
+diff -uN gfx/harfbuzz/src_old/hb-ot-os2-table.hh gfx/harfbuzz/src/hb-ot-os2-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-os2-table.hh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-os2-table.hh 2016-06-05 23:49:38.776917678 +0200
+@@ -0,0 +1,105 @@
++/*
++ * Copyright © 2011,2012 Google, Inc.
++ *
++ * This is part of HarfBuzz, a text shaping library.
++ *
++ * Permission is hereby granted, without written agreement and without
++ * license or royalty fees, to use, copy, modify, and distribute this
++ * software and its documentation for any purpose, provided that the
++ * above copyright notice and the following two paragraphs appear in
++ * all copies of this software.
++ *
++ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
++ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
++ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ *
++ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
++ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
++ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
++ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
++ *
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_OS2_TABLE_HH
++#define HB_OT_OS2_TABLE_HH
++
++#include "hb-open-type-private.hh"
++
++
++namespace OT {
++
++/*
++ * OS/2 and Windows Metrics
++ * http://www.microsoft.com/typography/otspec/os2.htm
++ */
++
++#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
++
++struct os2
++{
++ static const hb_tag_t tableTag = HB_OT_TAG_os2;
++
++ inline bool sanitize (hb_sanitize_context_t *c) const
++ {
++ TRACE_SANITIZE (this);
++ return_trace (c->check_struct (this));
++ }
++
++ public:
++ USHORT version;
++
++ /* Version 0 */
++ SHORT xAvgCharWidth;
++ USHORT usWeightClass;
++ USHORT usWidthClass;
++ USHORT fsType;
++ SHORT ySubscriptXSize;
++ SHORT ySubscriptYSize;
++ SHORT ySubscriptXOffset;
++ SHORT ySubscriptYOffset;
++ SHORT ySuperscriptXSize;
++ SHORT ySuperscriptYSize;
++ SHORT ySuperscriptXOffset;
++ SHORT ySuperscriptYOffset;
++ SHORT yStrikeoutSize;
++ SHORT yStrikeoutPosition;
++ SHORT sFamilyClass;
++ BYTE panose[10];
++ ULONG ulUnicodeRange[4];
++ Tag achVendID;
++ USHORT fsSelection;
++ USHORT usFirstCharIndex;
++ USHORT usLastCharIndex;
++ SHORT sTypoAscender;
++ SHORT sTypoDescender;
++ SHORT sTypoLineGap;
++ USHORT usWinAscent;
++ USHORT usWinDescent;
++
++ /* Version 1 */
++ //ULONG ulCodePageRange1;
++ //ULONG ulCodePageRange2;
++
++ /* Version 2 */
++ //SHORT sxHeight;
++ //SHORT sCapHeight;
++ //USHORT usDefaultChar;
++ //USHORT usBreakChar;
++ //USHORT usMaxContext;
++
++ /* Version 5 */
++ //USHORT usLowerOpticalPointSize;
++ //USHORT usUpperOpticalPointSize;
++
++ public:
++ DEFINE_SIZE_STATIC (78);
++};
++
++} /* namespace OT */
++
++
++#endif /* HB_OT_OS2_TABLE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape.cc gfx/harfbuzz/src/hb-ot-shape.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape.cc 2016-06-05 23:50:19.596703497 +0200
+@@ -59,10 +59,6 @@
+ HB_TAG('r','c','l','t'),
+ };
+
+-static hb_tag_t vertical_features[] = {
+- HB_TAG('v','e','r','t'),
+-};
+-
+
+
+ static void
+@@ -105,10 +101,13 @@
+ (horizontal_features[i] == HB_TAG('k','e','r','n') ?
+ F_HAS_FALLBACK : F_NONE));
+ else
+- for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
+- map->add_feature (vertical_features[i], 1, F_GLOBAL |
+- (vertical_features[i] == HB_TAG('v','k','r','n') ?
+- F_HAS_FALLBACK : F_NONE));
++ {
++ /* We really want to find a 'vert' feature if there's any in the font, no
++ * matter which script/langsys it is listed (or not) under.
++ * See various bugs referenced from:
++ * https://github.com/behdad/harfbuzz/issues/63 */
++ map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
++ }
+
+ if (planner->shaper->override_features)
+ planner->shaper->override_features (planner);
+@@ -229,7 +228,7 @@
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+- _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
++ _hb_glyph_info_set_unicode_props (&info[i], buffer);
+ }
+
+ static void
+@@ -246,7 +245,7 @@
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+- _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
++ _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
+
+ buffer->clear_output ();
+
+@@ -255,7 +254,7 @@
+ info.cluster = buffer->cur().cluster;
+ info.mask = buffer->cur().mask;
+ buffer->output_info (info);
+- while (buffer->idx < buffer->len)
++ while (buffer->idx < buffer->len && !buffer->in_error)
+ buffer->next_glyph ();
+
+ buffer->swap_buffers ();
+@@ -264,11 +263,23 @@
+ static void
+ hb_form_clusters (hb_buffer_t *buffer)
+ {
++ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
++ buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
++ return;
++
++ /* Loop duplicated in hb_ensure_native_direction(). */
++ unsigned int base = 0;
+ 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 (_hb_glyph_info_get_general_category (&info[i])))
+- buffer->merge_clusters (i - 1, i + 1);
++ {
++ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
++ {
++ buffer->merge_clusters (base, i);
++ base = i;
++ }
++ }
++ buffer->merge_clusters (base, count);
+ }
+
+ static void
+@@ -283,7 +294,28 @@
+ if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) ||
+ (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB))
+ {
+- hb_buffer_reverse_clusters (buffer);
++ /* Same loop as hb_form_clusters().
++ * Since form_clusters() merged clusters already, we don't merge. */
++ unsigned int base = 0;
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ for (unsigned int i = 1; i < count; i++)
++ {
++ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
++ {
++ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
++ buffer->merge_clusters (base, i);
++ buffer->reverse_range (base, i);
++
++ base = i;
++ }
++ }
++ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
++ buffer->merge_clusters (base, count);
++ buffer->reverse_range (base, count);
++
++ buffer->reverse ();
++
+ buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction);
+ }
+ }
+@@ -305,7 +337,7 @@
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++) {
+ hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+- if (likely (codepoint == info[i].codepoint))
++ if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint)))
+ info[i].mask |= rtlm_mask;
+ else
+ info[i].codepoint = codepoint;
+@@ -315,7 +347,8 @@
+ static inline void
+ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
+ {
+- if (!c->plan->has_frac)
++ if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
++ !c->plan->has_frac)
+ return;
+
+ hb_buffer_t *buffer = c->buffer;
+@@ -380,6 +413,103 @@
+ }
+ }
+
++static void
++hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
++{
++ hb_buffer_t *buffer = c->buffer;
++
++ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
++ (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
++ return;
++
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ hb_glyph_position_t *pos = buffer->pos;
++ unsigned int i = 0;
++ for (i = 0; i < count; i++)
++ if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
++ pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
++}
++
++static void
++hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
++{
++ hb_buffer_t *buffer = c->buffer;
++
++ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
++ (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
++ return;
++
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ hb_glyph_position_t *pos = buffer->pos;
++ unsigned int i = 0;
++ for (i = 0; i < count; i++)
++ {
++ if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
++ break;
++ }
++
++ /* No default-ignorables found; return. */
++ if (i == count)
++ return;
++
++ hb_codepoint_t space;
++ if (c->font->get_glyph (' ', 0, &space))
++ {
++ /* Replace default-ignorables with a zero-advance space glyph. */
++ for (/*continue*/; i < count; i++)
++ {
++ if (_hb_glyph_info_is_default_ignorable (&info[i]))
++ info[i].codepoint = space;
++ }
++ }
++ else
++ {
++ /* Merge clusters and delete default-ignorables.
++ * NOTE! We can't use out-buffer as we have positioning data. */
++ unsigned int j = i;
++ for (; i < count; i++)
++ {
++ if (_hb_glyph_info_is_default_ignorable (&info[i]))
++ {
++ /* Merge clusters.
++ * Same logic as buffer->delete_glyph(), but for in-place removal. */
++
++ unsigned int cluster = info[i].cluster;
++ if (i + 1 < count && cluster == info[i + 1].cluster)
++ continue; /* Cluster survives; do nothing. */
++
++ if (j)
++ {
++ /* Merge cluster backward. */
++ if (cluster < info[j - 1].cluster)
++ {
++ unsigned int old_cluster = info[j - 1].cluster;
++ for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--)
++ info[k - 1].cluster = cluster;
++ }
++ continue;
++ }
++
++ if (i + 1 < count)
++ buffer->merge_clusters (i, i + 2); /* Merge cluster forward. */
++
++ continue;
++ }
++
++ if (j != i)
++ {
++ info[j] = info[i];
++ pos[j] = pos[i];
++ }
++ j++;
++ }
++ buffer->len = j;
++ }
++}
++
++
+ static inline void
+ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
+ {
+@@ -388,6 +518,8 @@
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ info[i].codepoint = info[i].glyph_index();
++
++ buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+ }
+
+ static inline void
+@@ -397,7 +529,7 @@
+ hb_glyph_info_t *info = c->buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ {
+- hb_ot_layout_glyph_class_mask_t klass;
++ hb_ot_layout_glyph_props_flags_t klass;
+
+ /* Never mark default-ignorables as marks.
+ * They won't get in the way of lookups anyway,
+@@ -421,9 +553,6 @@
+ {
+ hb_buffer_t *buffer = c->buffer;
+
+- if (c->plan->shaper->preprocess_text)
+- c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
+-
+ hb_ot_shape_initialize_masks (c);
+
+ hb_ot_mirror_chars (c);
+@@ -448,7 +577,6 @@
+ {
+ hb_buffer_t *buffer = c->buffer;
+
+- _hb_buffer_allocate_gsubgpos_vars (buffer);
+ hb_ot_layout_substitute_start (c->font, buffer);
+
+ if (!hb_ot_layout_has_glyph_classes (c->face))
+@@ -465,6 +593,9 @@
+ hb_ot_substitute (hb_ot_shape_context_t *c)
+ {
+ hb_ot_substitute_default (c);
++
++ _hb_buffer_allocate_gsubgpos_vars (c->buffer);
++
+ hb_ot_substitute_complex (c);
+ }
+
+@@ -487,6 +618,9 @@
+ static inline void
+ zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
+ {
++ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
++ return;
++
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+@@ -501,6 +635,10 @@
+ static inline void
+ zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
+ {
++ /* This one is a hack; Technically GDEF can mark ASCII glyphs as marks, but we don't listen. */
++ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
++ return;
++
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+@@ -519,18 +657,30 @@
+ unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+- for (unsigned int i = 0; i < count; i++)
+- {
+- c->font->get_glyph_advance_for_direction (info[i].codepoint,
+- direction,
+- &pos[i].x_advance,
+- &pos[i].y_advance);
+- c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+- direction,
+- &pos[i].x_offset,
+- &pos[i].y_offset);
+
++ if (HB_DIRECTION_IS_HORIZONTAL (direction))
++ {
++ for (unsigned int i = 0; i < count; i++)
++ pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
++ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
++ if (c->font->has_glyph_h_origin_func ())
++ for (unsigned int i = 0; i < count; i++)
++ c->font->subtract_glyph_h_origin (info[i].codepoint,
++ &pos[i].x_offset,
++ &pos[i].y_offset);
++ }
++ else
++ {
++ for (unsigned int i = 0; i < count; i++)
++ {
++ pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
++ c->font->subtract_glyph_v_origin (info[i].codepoint,
++ &pos[i].x_offset,
++ &pos[i].y_offset);
++ }
+ }
++ if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
++ _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
+ }
+
+ static inline bool
+@@ -538,7 +688,7 @@
+ {
+ bool ret = false;
+ unsigned int count = c->buffer->len;
+- bool has_positioning = hb_ot_layout_has_positioning (c->face);
++ bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
+ /* If the font has no GPOS, AND, no fallback positioning will
+ * happen, AND, direction is forward, then when zeroing mark
+ * widths, we shift the mark with it, such that the mark
+@@ -575,23 +725,23 @@
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+
+- /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
++ /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
+
+- for (unsigned int i = 0; i < count; i++) {
+- c->font->add_glyph_origin_for_direction (info[i].codepoint,
+- HB_DIRECTION_LTR,
+- &pos[i].x_offset,
+- &pos[i].y_offset);
+- }
++ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
++ if (c->font->has_glyph_h_origin_func ())
++ for (unsigned int i = 0; i < count; i++)
++ c->font->add_glyph_h_origin (info[i].codepoint,
++ &pos[i].x_offset,
++ &pos[i].y_offset);
+
+ c->plan->position (c->font, c->buffer);
+
+- for (unsigned int i = 0; i < count; i++) {
+- c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+- HB_DIRECTION_LTR,
+- &pos[i].x_offset,
+- &pos[i].y_offset);
+- }
++ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
++ if (c->font->has_glyph_h_origin_func ())
++ for (unsigned int i = 0; i < count; i++)
++ c->font->subtract_glyph_h_origin (info[i].codepoint,
++ &pos[i].x_offset,
++ &pos[i].y_offset);
+
+ ret = true;
+ }
+@@ -625,6 +775,8 @@
+
+ hb_bool_t fallback = !hb_ot_position_complex (c);
+
++ hb_ot_zero_width_default_ignorables (c);
++
+ hb_ot_layout_position_finish (c->font, c->buffer);
+
+ if (fallback && c->plan->shaper->fallback_position)
+@@ -642,59 +794,18 @@
+ }
+
+
+-/* Post-process */
+-
+-static void
+-hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
+-{
+- if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+- return;
+-
+- hb_codepoint_t space;
+- enum {
+- SPACE_DONT_KNOW,
+- SPACE_AVAILABLE,
+- SPACE_UNAVAILABLE
+- } space_status = SPACE_DONT_KNOW;
+-
+- unsigned int count = c->buffer->len;
+- hb_glyph_info_t *info = c->buffer->info;
+- hb_glyph_position_t *pos = c->buffer->pos;
+- unsigned int j = 0;
+- for (unsigned int i = 0; i < count; i++)
+- {
+- if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
+- _hb_glyph_info_is_default_ignorable (&info[i])))
+- {
+- if (space_status == SPACE_DONT_KNOW)
+- space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
+-
+- if (space_status == SPACE_AVAILABLE)
+- {
+- info[i].codepoint = space;
+- pos[i].x_advance = 0;
+- pos[i].y_advance = 0;
+- }
+- else
+- continue; /* Delete it. */
+- }
+- if (j != i)
+- {
+- info[j] = info[i];
+- pos[j] = pos[i];
+- }
+- j++;
+- }
+- c->buffer->len = j;
+-}
+-
+-
+ /* Pull it all together! */
+
+ static void
+ hb_ot_shape_internal (hb_ot_shape_context_t *c)
+ {
+ c->buffer->deallocate_var_all ();
++ c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
++ if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
++ {
++ c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
++ (unsigned) HB_BUFFER_MAX_LEN_MIN);
++ }
+
+ /* Save the original direction, we use it later. */
+ c->target_direction = c->buffer->props.direction;
+@@ -709,15 +820,22 @@
+
+ hb_ensure_native_direction (c->buffer);
+
++ if (c->plan->shaper->preprocess_text)
++ c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
++
+ hb_ot_substitute (c);
+ hb_ot_position (c);
+
+ hb_ot_hide_default_ignorables (c);
+
++ if (c->plan->shaper->postprocess_glyphs)
++ c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
++
+ _hb_buffer_deallocate_unicode_vars (c->buffer);
+
+ c->buffer->props.direction = c->target_direction;
+
++ c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+ c->buffer->deallocate_var_all ();
+ }
+
+@@ -736,6 +854,11 @@
+ }
+
+
++/**
++ * hb_ot_shape_plan_collect_lookups:
++ *
++ * Since: 0.9.7
++ **/
+ void
+ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+ hb_tag_t table_tag,
+@@ -766,6 +889,11 @@
+ }
+
+
++/**
++ * hb_ot_shape_glyphs_closure:
++ *
++ * Since: 0.9.2
++ **/
+ void
+ hb_ot_shape_glyphs_closure (hb_font_t *font,
+ hb_buffer_t *buffer,
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic.cc gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc 2016-06-05 23:49:45.590881534 +0200
+@@ -24,18 +24,51 @@
+ * Google Author(s): Behdad Esfahbod
+ */
+
+-#include "hb-ot-shape-complex-private.hh"
++#include "hb-ot-shape-complex-arabic-private.hh"
+ #include "hb-ot-shape-private.hh"
+
+
++#ifndef HB_DEBUG_ARABIC
++#define HB_DEBUG_ARABIC (HB_DEBUG+0)
++#endif
++
++
+ /* buffer var allocations */
+ #define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+
++#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
++
++/* See:
++ * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
++#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
++ (FLAG_SAFE (gen_cat) & \
++ (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
++ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
++ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
++ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
++
++
++/*
++ * Joining types:
++ */
+
+ /*
+ * Bits used in the joining tables
+ */
+-enum {
++enum hb_arabic_joining_type_t {
+ JOINING_TYPE_U = 0,
+ JOINING_TYPE_L = 1,
+ JOINING_TYPE_R = 2,
+@@ -49,10 +82,6 @@
+ JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
+ };
+
+-/*
+- * Joining types:
+- */
+-
+ #include "hb-ot-shape-complex-arabic-table.hh"
+
+ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
+@@ -61,7 +90,7 @@
+ if (likely (j_type != JOINING_TYPE_X))
+ return j_type;
+
+- return (FLAG(gen_cat) &
++ return (FLAG_SAFE(gen_cat) &
+ (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
+ FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
+ FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
+@@ -84,7 +113,7 @@
+
+
+ /* Same order as the feature array */
+-enum {
++enum arabic_action_t {
+ ISOL,
+ FINA,
+ FIN2,
+@@ -95,7 +124,11 @@
+
+ NONE,
+
+- ARABIC_NUM_FEATURES = NONE
++ ARABIC_NUM_FEATURES = NONE,
++
++ /* We abuse the same byte for other things... */
++ STCH_FIXED,
++ STCH_REPEATING,
+ };
+
+ static const struct arabic_state_table_entry {
+@@ -140,6 +173,11 @@
+ hb_buffer_t *buffer);
+
+ static void
++record_stch (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++
++static void
+ collect_features_arabic (hb_ot_shape_planner_t *plan)
+ {
+ hb_ot_map_builder_t *map = &plan->map;
+@@ -165,6 +203,9 @@
+
+ map->add_gsub_pause (nuke_joiners);
+
++ map->add_global_bool_feature (HB_TAG('s','t','c','h'));
++ map->add_gsub_pause (record_stch);
++
+ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+
+@@ -182,7 +223,6 @@
+ map->add_gsub_pause (arabic_fallback_shape);
+
+ map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+- map->add_gsub_pause (NULL);
+
+ /* The spec includes 'cswh'. Earlier versions of Windows
+ * used to enable this by default, but testing suggests
+@@ -192,6 +232,7 @@
+ * Note that IranNastaliq uses this feature extensively
+ * to fixup broken glyph sequences. Oh well...
+ * Test case: U+0643,U+0640,U+0631. */
++ //map->add_gsub_pause (NULL);
+ //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
+ map->add_global_bool_feature (HB_TAG('m','s','e','t'));
+ }
+@@ -208,11 +249,13 @@
+ * mask_array[NONE] == 0. */
+ hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
+
+- bool do_fallback;
+ arabic_fallback_plan_t *fallback_plan;
++
++ unsigned int do_fallback : 1;
++ unsigned int has_stch : 1;
+ };
+
+-static void *
++void *
+ data_create_arabic (const hb_ot_shape_plan_t *plan)
+ {
+ arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+@@ -220,6 +263,7 @@
+ return NULL;
+
+ arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
++ arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
+ for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
+ arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
+ arabic_plan->do_fallback = arabic_plan->do_fallback &&
+@@ -230,7 +274,7 @@
+ return arabic_plan;
+ }
+
+-static void
++void
+ data_destroy_arabic (void *data)
+ {
+ arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
+@@ -305,25 +349,30 @@
+ info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
+ }
+
+-static void
+-setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+- hb_buffer_t *buffer,
+- hb_font_t *font HB_UNUSED)
++void
++setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
++ hb_buffer_t *buffer,
++ hb_script_t script)
+ {
+ HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+
+- const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+-
+ arabic_joining (buffer);
+- if (plan->props.script == HB_SCRIPT_MONGOLIAN)
++ if (script == HB_SCRIPT_MONGOLIAN)
+ mongolian_variation_selectors (buffer);
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
++}
+
+- HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
++static void
++setup_masks_arabic (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer,
++ hb_font_t *font HB_UNUSED)
++{
++ const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
++ setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
+ }
+
+
+@@ -364,6 +413,197 @@
+ arabic_fallback_plan_shape (fallback_plan, font, buffer);
+ }
+
++/*
++ * Stretch feature: "stch".
++ * See example here:
++ * https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
++ * We implement this in a generic way, such that the Arabic subtending
++ * marks can use it as well.
++ */
++
++static void
++record_stch (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
++ if (!arabic_plan->has_stch)
++ return;
++
++ /* 'stch' feature was just applied. Look for anything that multiplied,
++ * and record it for stch treatment later. Note that rtlm, frac, etc
++ * are applied before stch, but we assume that they didn't result in
++ * anything multiplying into 5 pieces, so it's safe-ish... */
++
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ for (unsigned int i = 0; i < count; i++)
++ if (unlikely (_hb_glyph_info_multiplied (&info[i])))
++ {
++ unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
++ info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
++ }
++}
++
++static void
++apply_stch (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer,
++ hb_font_t *font)
++{
++ if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
++ return;
++
++ /* The Arabic shaper currently always processes in RTL mode, so we should
++ * stretch / position the stretched pieces to the left / preceding glyphs. */
++
++ /* We do a two pass implementation:
++ * First pass calculates the exact number of extra glyphs we need,
++ * We then enlarge buffer to have that much room,
++ * Second pass applies the stretch, copying things to the end of buffer.
++ */
++
++ int sign = font->x_scale < 0 ? -1 : +1;
++ unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
++ typedef enum { MEASURE, CUT } step_t;
++
++ for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
++ {
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ hb_glyph_position_t *pos = buffer->pos;
++ unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
++ unsigned int j = new_len;
++ for (unsigned int i = count; i; i--)
++ {
++ if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
++ {
++ if (step == CUT)
++ {
++ --j;
++ info[j] = info[i - 1];
++ pos[j] = pos[i - 1];
++ }
++ continue;
++ }
++
++ /* Yay, justification! */
++
++ hb_position_t w_total = 0; // Total to be filled
++ hb_position_t w_fixed = 0; // Sum of fixed tiles
++ hb_position_t w_repeating = 0; // Sum of repeating tiles
++ int n_fixed = 0;
++ int n_repeating = 0;
++
++ unsigned int end = i;
++ while (i &&
++ hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
++ {
++ i--;
++ hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
++ if (info[i].arabic_shaping_action() == STCH_FIXED)
++ {
++ w_fixed += width;
++ n_fixed++;
++ }
++ else
++ {
++ w_repeating += width;
++ n_repeating++;
++ }
++ }
++ unsigned int start = i;
++ unsigned int context = i;
++ while (context &&
++ !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
++ (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
++ HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
++ {
++ context--;
++ w_total += pos[context].x_advance;
++ }
++ i++; // Don't touch i again.
++
++ DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
++ step == MEASURE ? "measuring" : "cutting", context, start, end);
++ DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - context, w_total);
++ DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
++ DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
++
++ /* Number of additional times to repeat each repeating tile. */
++ int n_copies = 0;
++
++ hb_position_t w_remaining = w_total - w_fixed;
++ if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
++ n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
++
++ /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
++ hb_position_t extra_repeat_overlap = 0;
++ hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
++ if (shortfall > 0)
++ {
++ ++n_copies;
++ hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
++ if (excess > 0)
++ extra_repeat_overlap = excess / (n_copies * n_repeating);
++ }
++
++ if (step == MEASURE)
++ {
++ extra_glyphs_needed += n_copies * n_repeating;
++ DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
++ }
++ else
++ {
++ hb_position_t x_offset = 0;
++ for (unsigned int k = end; k > start; k--)
++ {
++ hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
++
++ unsigned int repeat = 1;
++ if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
++ repeat += n_copies;
++
++ DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
++ repeat, info[k - 1].codepoint, j);
++ for (unsigned int n = 0; n < repeat; n++)
++ {
++ x_offset -= width;
++ if (n > 0)
++ x_offset += extra_repeat_overlap;
++ pos[k - 1].x_offset = x_offset;
++ /* Append copy. */
++ --j;
++ info[j] = info[k - 1];
++ pos[j] = pos[k - 1];
++ }
++ }
++ }
++ }
++
++ if (step == MEASURE)
++ {
++ if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
++ break;
++ }
++ else
++ {
++ assert (j == 0);
++ buffer->len = new_len;
++ }
++ }
++}
++
++
++static void
++postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer,
++ hb_font_t *font)
++{
++ apply_stch (plan, buffer, font);
++
++ HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
++}
+
+ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+ {
+@@ -372,7 +612,8 @@
+ NULL, /* override_features */
+ data_create_arabic,
+ data_destroy_arabic,
+- NULL, /* preprocess_text_arabic */
++ NULL, /* preprocess_text */
++ postprocess_glyphs_arabic,
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-fallback.hh gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-fallback.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh 2016-06-05 23:49:40.225909984 +0200
+@@ -75,9 +75,9 @@
+ if (!num_glyphs)
+ return NULL;
+
+- /* Bubble-sort!
++ /* Bubble-sort or something equally good!
+ * May not be good-enough for presidential candidate interviews, but good-enough for us... */
+- hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
++ hb_stable_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
+
+ OT::Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs);
+ OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
+@@ -126,7 +126,7 @@
+ first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
+ num_first_glyphs++;
+ }
+- hb_bubble_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
++ hb_stable_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+
+ /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
+ for (unsigned int i = 0; i < num_first_glyphs; i++)
+@@ -327,7 +327,7 @@
+ for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+ if (fallback_plan->lookup_array[i])
+ {
+- fallback_plan->accel_array[i].fini (fallback_plan->lookup_array[i]);
++ fallback_plan->accel_array[i].fini ();
+ if (fallback_plan->free_lookups)
+ free (fallback_plan->lookup_array[i]);
+ }
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-private.hh gfx/harfbuzz/src/hb-ot-shape-complex-arabic-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-private.hh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-arabic-private.hh 2016-06-05 23:49:41.475903336 +0200
+@@ -0,0 +1,50 @@
++/*
++ * Copyright © 2015 Mozilla Foundation.
++ * Copyright © 2015 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.
++ *
++ * Mozilla Author(s): Jonathan Kew
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
++#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
++
++#include "hb-private.hh"
++
++#include "hb-ot-shape-complex-private.hh"
++
++
++struct arabic_shape_plan_t;
++
++HB_INTERNAL void *
++data_create_arabic (const hb_ot_shape_plan_t *plan);
++
++HB_INTERNAL void
++data_destroy_arabic (void *data);
++
++HB_INTERNAL void
++setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
++ hb_buffer_t *buffer,
++ hb_script_t script);
++
++#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-table.hh gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-table.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh 2016-06-05 23:49:42.902895782 +0200
+@@ -6,10 +6,10 @@
+ *
+ * on files with these headers:
+ *
+- * # ArabicShaping-7.0.0.txt
+- * # Date: 2014-02-14, 21:00:00 GMT [RP, KW, LI]
+- * # Blocks-7.0.0.txt
+- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
++ * # ArabicShaping-8.0.0.txt
++ * # Date: 2015-02-17, 23:33:00 GMT [RP]
++ * # Blocks-8.0.0.txt
++ * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ * UnicodeData.txt does not have a header.
+ */
+
+@@ -76,9 +76,9 @@
+
+ /* Arabic Extended-A */
+
+- /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,
++ /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,
+
+-#define joining_offset_0x1806u 691
++#define joining_offset_0x1806u 693
+
+ /* Mongolian */
+
+@@ -89,40 +89,40 @@
+ /* 1880 */ U,U,U,U,U,U,U,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
+
+-#define joining_offset_0x200cu 856
++#define joining_offset_0x200cu 858
+
+ /* General Punctuation */
+
+ /* 2000 */ U,C,
+
+-#define joining_offset_0x2066u 858
++#define joining_offset_0x2066u 860
+
+ /* General Punctuation */
+
+ /* 2060 */ U,U,U,U,
+
+-#define joining_offset_0xa840u 862
++#define joining_offset_0xa840u 864
+
+ /* Phags-pa */
+
+ /* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
+
+-#define joining_offset_0x10ac0u 914
++#define joining_offset_0x10ac0u 916
+
+ /* Manichaean */
+
+ /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
+ /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
+
+-#define joining_offset_0x10b80u 962
++#define joining_offset_0x10b80u 964
+
+ /* Psalter Pahlavi */
+
+ /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
+
+-}; /* Table items: 1010; occupancy: 57% */
++}; /* Table items: 1012; occupancy: 57% */
+
+
+ static unsigned int
+@@ -131,7 +131,7 @@
+ switch (u >> 12)
+ {
+ case 0x0u:
+- if (hb_in_range (u, 0x0600u, 0x08B2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
++ if (hb_in_range (u, 0x0600u, 0x08B4u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+ break;
+
+ case 0x1u:
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-win1256.hh gfx/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-arabic-win1256.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh 2016-06-05 23:49:44.102889415 +0200
+@@ -133,7 +133,6 @@
+ */
+
+ #define OT_LOOKUP_TYPE_SUBST_SINGLE 1u
+-#define OT_LOOKUP_TYPE_SUBST_MULTIPLE 2u
+ #define OT_LOOKUP_TYPE_SUBST_LIGATURE 4u
+
+ #define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
+@@ -143,7 +142,7 @@
+ OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
+- /* ASSERT_STATIC_EXPR len(FromGlyphs) == len(ToGlyphs) */
++ /* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+
+ #define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
+ OT_SUBLOOKUP(Name, 1, \
+@@ -152,7 +151,7 @@
+ OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
+- /* ASSERT_STATIC_EXPR len(FirstGlyphs) == len(LigatureSetOffsets) */
++ /* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+
+ #define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
+ OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-default.cc gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-default.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-default.cc 2016-06-05 23:49:46.803875109 +0200
+@@ -35,10 +35,11 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ true, /* fallback_position */
+ };
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-hangul.cc gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-hangul.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-hangul.cc 2016-06-05 23:49:47.978868903 +0200
+@@ -188,7 +188,7 @@
+ */
+ unsigned int count = buffer->len;
+
+- for (buffer->idx = 0; buffer->idx < count;)
++ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+ {
+ hb_codepoint_t u = buffer->cur().codepoint;
+
+@@ -205,17 +205,12 @@
+ buffer->next_glyph ();
+ if (!is_zero_width_char (font, u))
+ {
++ buffer->merge_out_clusters (start, end + 1);
+ hb_glyph_info_t *info = buffer->out_info;
+ hb_glyph_info_t tone = info[end];
+ memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
+ info[start] = tone;
+ }
+- /* Merge clusters across the (possibly reordered) syllable+tone.
+- * We want to merge even in the zero-width tone mark case here,
+- * so that clustering behavior isn't dependent on how the tone mark
+- * is handled by the font.
+- */
+- buffer->merge_out_clusters (start, end + 1);
+ }
+ else
+ {
+@@ -296,7 +291,8 @@
+ }
+ else
+ end = start + 2;
+- buffer->merge_out_clusters (start, end);
++ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
++ buffer->merge_out_clusters (start, end);
+ continue;
+ }
+ }
+@@ -368,7 +364,8 @@
+ info[i++].hangul_shaping_feature() = VJMO;
+ if (i < end)
+ info[i++].hangul_shaping_feature() = TJMO;
+- buffer->merge_out_clusters (start, end);
++ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
++ buffer->merge_out_clusters (start, end);
+ continue;
+ }
+ }
+@@ -414,13 +411,14 @@
+ "hangul",
+ collect_features_hangul,
+ override_features_hangul,
+- data_create_hangul, /* data_create */
+- data_destroy_hangul, /* data_destroy */
++ data_create_hangul,
++ data_destroy_hangul,
+ preprocess_text_hangul,
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
+ NULL, /* decompose */
+ NULL, /* compose */
+- setup_masks_hangul, /* setup_masks */
++ setup_masks_hangul,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ false, /* fallback_position */
+ };
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-hebrew.cc gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-hebrew.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc 2016-06-05 23:49:49.094863009 +0200
+@@ -68,7 +68,7 @@
+ 0xFB4Au /* TAV */
+ };
+
+- bool found = c->unicode->compose (a, b, ab);
++ bool found = (bool) c->unicode->compose (a, b, ab);
+
+ if (!found && !c->plan->has_mark)
+ {
+@@ -163,6 +163,7 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ compose_hebrew,
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-indic.cc gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-indic.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc 2016-06-05 23:49:56.649823205 +0200
+@@ -142,7 +142,7 @@
+ {
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+- return !!(FLAG (info.indic_category()) & flags);
++ return !!(FLAG_SAFE (info.indic_category()) & flags);
+ }
+
+ static inline bool
+@@ -176,24 +176,8 @@
+ * Re-assign category
+ */
+
+-
+- /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
+- * treats a whole bunch of characters similarly.
+- * TESTS: For example, for U+0951:
+- * U+092E,U+0947,U+0952
+- * U+092E,U+0952,U+0947
+- * U+092E,U+0947,U+0951
+- * U+092E,U+0951,U+0947
+- * U+092E,U+0951,U+0952
+- * U+092E,U+0952,U+0951
+- */
+- if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
+- 0x1CD0u, 0x1CD2u,
+- 0x1CD4u, 0x1CE1u) ||
+- u == 0x1CF4u))
+- cat = OT_A;
+ /* The following act more like the Bindus. */
+- else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
++ if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+ cat = OT_SM;
+ /* The following act like consonants. */
+ else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
+@@ -216,15 +200,12 @@
+ cat = OT_Symbol;
+ ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+ }
+- else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
+- u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
++ else if (unlikely (u == 0x17DDu)) /* https://github.com/roozbehp/unicode-data/issues/2 */
+ {
+- /* These are like Top Matras. */
+ cat = OT_M;
+ pos = POS_ABOVE_C;
+ }
+ else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
+- else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
+ else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
+ cat = OT_PLACEHOLDER;
+ else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
+@@ -237,7 +218,7 @@
+ * Re-assign position.
+ */
+
+- if ((FLAG (cat) & CONSONANT_FLAGS))
++ if ((FLAG_SAFE (cat) & CONSONANT_FLAGS))
+ {
+ pos = POS_BASE_C;
+ if (is_ra (u))
+@@ -247,7 +228,7 @@
+ {
+ pos = matra_position (u, pos);
+ }
+- else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
++ else if ((FLAG_SAFE (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+ {
+ pos = POS_SMVD;
+ }
+@@ -557,8 +538,15 @@
+ indic_plan->virama_glyph = (hb_codepoint_t) -1;
+
+ /* Use zero-context would_substitute() matching for new-spec of the main
+- * Indic scripts, and scripts with one spec only, but not for old-specs. */
+- bool zero_context = !indic_plan->is_old_spec;
++ * Indic scripts, and scripts with one spec only, but not for old-specs.
++ * The new-spec for all dual-spec scripts says zero-context matching happens.
++ *
++ * However, testing with Malayalam shows that old and new spec both allow
++ * context. Testing with Bengali new-spec however shows that it doesn't.
++ * So, the heuristic here is the way it is. It should *only* be changed,
++ * as we discover more cases of what Windows does. DON'T TOUCH OTHERWISE.
++ */
++ bool zero_context = !indic_plan->is_old_spec && plan->props.script != HB_SCRIPT_MALAYALAM;
+ indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+ indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+ indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+@@ -756,7 +744,7 @@
+ {
+ default:
+ assert (false);
+- /* fallthrough */
++ HB_FALLTHROUGH;
+
+ case BASE_POS_LAST:
+ {
+@@ -963,7 +951,7 @@
+ indic_position_t last_pos = POS_START;
+ for (unsigned int i = start; i < end; i++)
+ {
+- if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
++ if ((FLAG_SAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+ {
+ info[i].indic_position() = last_pos;
+ if (unlikely (info[i].indic_category() == OT_H &&
+@@ -1012,7 +1000,7 @@
+ info[i].syllable() = i - start;
+
+ /* Sit tight, rock 'n roll! */
+- hb_bubble_sort (info + start, end - start, compare_indic_order);
++ hb_stable_sort (info + start, end - start, compare_indic_order);
+ /* Find base again */
+ base = end;
+ for (unsigned int i = start; i < end; i++)
+@@ -1025,7 +1013,11 @@
+ * around like crazy. In old-spec mode, we move halants around, so in
+ * that case merge all clusters after base. Otherwise, check the sort
+ * order and merge as needed.
+- * For pre-base stuff, we handle cluster issues in final reordering. */
++ * For pre-base stuff, we handle cluster issues in final reordering.
++ *
++ * We could use buffer->sort() for this, if there was no special
++ * reordering of pre-base stuff happening later...
++ */
+ if (indic_plan->is_old_spec || end - base > 127)
+ buffer->merge_clusters (base, end);
+ else
+@@ -1161,17 +1153,6 @@
+ }
+ }
+
+-
+-static void
+-initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- /* We made the vowels look like consonants. So let's call the consonant logic! */
+- initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+-}
+-
+ static void
+ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+@@ -1194,50 +1175,27 @@
+ }
+
+ static void
+-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- /* We already inserted dotted-circles, so just call the standalone_cluster. */
+- initial_reordering_standalone_cluster (plan, face, buffer, start, end);
+-}
+-
+-static void
+-initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_face_t *face HB_UNUSED,
+- hb_buffer_t *buffer HB_UNUSED,
+- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+-{
+- /* Nothing to do right now. If we ever switch to using the output
+- * buffer in the reordering process, we'd need to next_glyph() here. */
+-}
+-
+-static void
+-initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_face_t *face HB_UNUSED,
+- hb_buffer_t *buffer HB_UNUSED,
+- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+-{
+- /* Nothing to do right now. If we ever switch to using the output
+- * buffer in the reordering process, we'd need to next_glyph() here. */
+-}
+-
+-
+-static void
+ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+ {
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+- switch (syllable_type) {
+- case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+- case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
+- case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
+- case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return;
+- case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+- case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
++ switch (syllable_type)
++ {
++ case vowel_syllable: /* We made the vowels look like consonants. So let's call the consonant logic! */
++ case consonant_syllable:
++ initial_reordering_consonant_syllable (plan, face, buffer, start, end);
++ break;
++
++ case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */
++ case standalone_cluster:
++ initial_reordering_standalone_cluster (plan, face, buffer, start, end);
++ break;
++
++ case symbol_cluster:
++ case non_indic_cluster:
++ break;
+ }
+ }
+
+@@ -1273,7 +1231,7 @@
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+- while (buffer->idx < buffer->len)
++ while (buffer->idx < buffer->len && !buffer->in_error)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+@@ -1281,10 +1239,10 @@
+ {
+ last_syllable = syllable;
+
+- hb_glyph_info_t info = dottedcircle;
+- info.cluster = buffer->cur().cluster;
+- info.mask = buffer->cur().mask;
+- info.syllable() = buffer->cur().syllable();
++ hb_glyph_info_t ginfo = dottedcircle;
++ ginfo.cluster = buffer->cur().cluster;
++ ginfo.mask = buffer->cur().mask;
++ ginfo.syllable() = buffer->cur().syllable();
+ /* TODO Set glyph_props? */
+
+ /* Insert dottedcircle after possible Repha. */
+@@ -1293,7 +1251,7 @@
+ buffer->cur().indic_category() == OT_Repha)
+ buffer->next_glyph ();
+
+- buffer->output_info (info);
++ buffer->output_info (ginfo);
+ }
+ else
+ buffer->next_glyph ();
+@@ -1310,18 +1268,8 @@
+ update_consonant_positions (plan, font, buffer);
+ insert_dotted_circles (plan, font, buffer);
+
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int count = buffer->len;
+- if (unlikely (!count)) return;
+- unsigned int last = 0;
+- unsigned int last_syllable = info[0].syllable();
+- for (unsigned int i = 1; i < count; i++)
+- if (last_syllable != info[i].syllable()) {
+- initial_reordering_syllable (plan, font->face, buffer, last, i);
+- last = i;
+- last_syllable = info[last].syllable();
+- }
+- initial_reordering_syllable (plan, font->face, buffer, last, count);
++ foreach_syllable (buffer, start, end)
++ initial_reordering_syllable (plan, font->face, buffer, start, end);
+ }
+
+ static void
+@@ -1388,6 +1336,25 @@
+ break;
+ }
+ }
++ /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
++ if (buffer->props.script == HB_SCRIPT_MALAYALAM)
++ {
++ for (unsigned int i = base + 1; i < end; i++)
++ {
++ while (i < end && is_joiner (info[i]))
++ i++;
++ if (i == end || !is_halant_or_coeng (info[i]))
++ break;
++ i++; /* Skip halant. */
++ while (i < end && is_joiner (info[i]))
++ i++;
++ if (i < end && is_consonant (info[i]) && info[i].indic_position() == POS_BELOW_C)
++ {
++ base = i;
++ info[base].indic_position() = POS_BASE_C;
++ }
++ }
++ }
+
+ if (start < base && info[base].indic_position() > POS_BASE_C)
+ base--;
+@@ -1448,12 +1415,17 @@
+ if (info[i - 1].indic_position () == POS_PRE_M)
+ {
+ unsigned int old_pos = i - 1;
++ if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
++ base--;
++
+ hb_glyph_info_t tmp = info[old_pos];
+ memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
+ info[new_pos] = tmp;
+- if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
+- base--;
++
++ /* Note: this merge_clusters() is intentionally *after* the reordering.
++ * Indic matra reordering is special and tricky... */
+ buffer->merge_clusters (new_pos, MIN (end, base + 1));
++
+ new_pos--;
+ }
+ } else {
+@@ -1550,7 +1522,7 @@
+ {
+ new_reph_pos = base;
+ while (new_reph_pos < end &&
+- !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
++ !( FLAG_SAFE (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
+ new_reph_pos++;
+ if (new_reph_pos < end)
+ goto reph_move;
+@@ -1606,12 +1578,12 @@
+
+ reph_move:
+ {
+- buffer->merge_clusters (start, new_reph_pos + 1);
+-
+ /* Move */
++ buffer->merge_clusters (start, new_reph_pos + 1);
+ hb_glyph_info_t reph = info[start];
+ memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
+ info[new_reph_pos] = reph;
++
+ if (start < base && base <= new_reph_pos)
+ base--;
+ }
+@@ -1666,8 +1638,8 @@
+ if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
+ {
+ unsigned int old_pos = i;
+- for (unsigned int i = base + 1; i < old_pos; i++)
+- if (info[i].indic_category() == OT_M)
++ for (unsigned int j = base + 1; j < old_pos; j++)
++ if (info[j].indic_category() == OT_M)
+ {
+ new_pos--;
+ break;
+@@ -1684,10 +1656,12 @@
+
+ {
+ unsigned int old_pos = i;
++
+ buffer->merge_clusters (new_pos, old_pos + 1);
+ hb_glyph_info_t tmp = info[old_pos];
+ memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
+ info[new_pos] = tmp;
++
+ if (new_pos <= base && base < old_pos)
+ base++;
+ }
+@@ -1701,7 +1675,7 @@
+ /* Apply 'init' to the Left Matra if it's a word start. */
+ if (info[start].indic_position () == POS_PRE_M &&
+ (!start ||
+- !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
++ !(FLAG_SAFE (_hb_glyph_info_get_general_category (&info[start - 1])) &
+ FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
+ info[start].mask |= indic_plan->mask_array[INIT];
+
+@@ -1737,16 +1711,8 @@
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int last = 0;
+- unsigned int last_syllable = info[0].syllable();
+- for (unsigned int i = 1; i < count; i++)
+- if (last_syllable != info[i].syllable()) {
+- final_reordering_syllable (plan, buffer, last, i);
+- last = i;
+- last_syllable = info[last].syllable();
+- }
+- final_reordering_syllable (plan, buffer, last, count);
++ foreach_syllable (buffer, start, end)
++ final_reordering_syllable (plan, buffer, start, end);
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
+@@ -1847,7 +1813,7 @@
+ }
+ }
+
+- return c->unicode->decompose (ab, a, b);
++ return (bool) c->unicode->decompose (ab, a, b);
+ }
+
+ static bool
+@@ -1863,7 +1829,7 @@
+ /* Composition-exclusion exceptions that we want to recompose. */
+ if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
+
+- return c->unicode->compose (a, b, ab);
++ return (bool) c->unicode->compose (a, b, ab);
+ }
+
+
+@@ -1875,6 +1841,7 @@
+ data_create_indic,
+ data_destroy_indic,
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ decompose_indic,
+ compose_indic,
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-machine.hh gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-machine.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh 2016-06-05 23:49:50.772854137 +0200
+@@ -1,5 +1,5 @@
+
+-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 1 "hb-ot-shape-complex-indic-machine.rl"
+ /*
+ * Copyright © 2011,2012 Google, Inc.
+ *
+@@ -32,1281 +32,1304 @@
+ #include "hb-private.hh"
+
+
+-#line 36 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 36 "hb-ot-shape-complex-indic-machine.hh"
+ static const unsigned char _indic_syllable_machine_trans_keys[] = {
+- 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u,
+- 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u,
+- 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u,
+- 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+- 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u,
+- 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u,
+- 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u,
+- 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u,
++ 8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
++ 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u,
++ 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
++ 4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
++ 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u,
++ 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
++ 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
++ 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
+ 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+- 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u,
+- 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u,
+- 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u,
+- 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+- 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, 13u, 13u, 5u, 7u, 5u, 7u, 7u, 7u,
+- 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u,
+- 7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u,
+- 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u,
+- 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
+- 4u, 14u, 5u, 7u, 5u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u,
+- 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 1u, 16u, 13u, 13u, 4u, 4u, 6u, 6u,
+- 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u,
+- 6u, 6u, 16u, 16u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
++ 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u, 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u,
++ 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
++ 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
++ 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u,
++ 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 8u, 8u, 1u, 16u,
++ 8u, 13u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
++ 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u,
++ 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
++ 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u,
++ 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 5u, 8u, 4u, 14u, 4u, 14u, 5u, 8u,
++ 5u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
++ 5u, 7u, 7u, 7u, 8u, 8u, 1u, 16u, 8u, 13u, 4u, 8u, 6u, 6u, 16u, 16u,
++ 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
++ 16u, 16u, 8u, 8u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u,
++ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
+ 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
+- 3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
++ 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
+- 6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
++ 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 31u, 3u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u,
++ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
+ 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
+- 3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
++ 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
+- 6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
++ 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 4u, 14u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u,
+ 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u,
+- 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u, 5u, 10u,
++ 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 5u, 10u,
+ 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u,
+- 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
+- 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u,
++ 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
++ 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 4u, 14u, 3u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
+- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 8u, 14u,
++ 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
+ 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
+- 3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
++ 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
+- 6u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
++ 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+- 1u, 16u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 14u, 1u, 16u, 3u, 31u,
+- 3u, 31u, 4u, 31u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u,
+- 5u, 10u, 3u, 31u, 3u, 31u, 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
+- 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 8u, 14u,
+- 3u, 13u, 3u, 10u, 8u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 3u, 10u, 8u, 10u,
++ 1u, 16u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 14u, 5u, 10u, 9u, 10u,
++ 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 1u, 16u, 3u, 31u, 3u, 31u,
++ 4u, 31u, 3u, 31u, 3u, 31u, 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
++ 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
++ 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 3u, 10u, 5u, 10u,
+ 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 0
+ };
+
+ static const char _indic_syllable_machine_key_spans[] = {
+- 16, 1, 3, 3, 1, 3, 3, 1,
+- 3, 3, 1, 3, 3, 1, 1, 1,
+- 1, 4, 1, 1, 4, 1, 1, 4,
+- 1, 1, 11, 11, 11, 11, 11, 11,
+- 11, 11, 11, 11, 16, 1, 3, 3,
+- 1, 3, 3, 1, 3, 3, 1, 3,
+- 3, 1, 1, 1, 1, 4, 1, 1,
+- 4, 1, 1, 4, 1, 1, 11, 11,
+- 11, 11, 11, 11, 11, 11, 11, 11,
+- 16, 1, 3, 3, 1, 3, 3, 1,
+- 3, 3, 1, 3, 3, 1, 1, 1,
+- 1, 4, 1, 1, 4, 1, 1, 4,
+- 1, 1, 11, 11, 11, 11, 11, 11,
+- 11, 11, 11, 16, 1, 3, 3, 1,
+- 3, 3, 1, 3, 3, 1, 3, 3,
+- 1, 1, 1, 1, 4, 1, 1, 4,
+- 1, 1, 4, 1, 1, 11, 11, 11,
++ 1, 16, 6, 4, 3, 1, 4, 3,
++ 1, 4, 3, 1, 4, 3, 1, 5,
++ 1, 1, 5, 1, 1, 5, 1, 1,
++ 5, 1, 1, 11, 11, 11, 11, 11,
++ 11, 11, 11, 11, 11, 1, 16, 6,
++ 4, 3, 1, 4, 3, 1, 4, 3,
++ 1, 4, 3, 1, 5, 1, 1, 5,
++ 1, 1, 5, 1, 1, 5, 1, 1,
+ 11, 11, 11, 11, 11, 11, 11, 11,
+- 11, 3, 3, 3, 3, 1, 3, 3,
+- 1, 3, 3, 1, 16, 1, 1, 1,
+- 1, 4, 1, 1, 4, 1, 1, 4,
++ 11, 11, 1, 16, 6, 4, 3, 1,
++ 4, 3, 1, 4, 3, 1, 4, 3,
++ 1, 5, 1, 1, 5, 1, 1, 5,
++ 1, 1, 5, 1, 1, 11, 11, 11,
++ 11, 11, 11, 11, 11, 11, 1, 16,
++ 6, 4, 3, 1, 4, 3, 1, 4,
++ 3, 1, 4, 3, 1, 5, 1, 1,
++ 5, 1, 1, 5, 1, 1, 5, 1,
++ 1, 11, 11, 11, 11, 11, 11, 11,
++ 11, 11, 11, 11, 4, 11, 11, 4,
++ 3, 4, 3, 1, 4, 3, 1, 4,
++ 3, 1, 1, 16, 6, 5, 1, 1,
++ 5, 1, 1, 5, 1, 1, 5, 1,
+ 1, 1, 31, 29, 29, 28, 16, 29,
+ 29, 28, 16, 29, 29, 28, 16, 29,
+- 29, 28, 16, 29, 29, 28, 10, 7,
++ 29, 28, 16, 29, 29, 28, 10, 10,
+ 6, 2, 1, 2, 2, 1, 6, 11,
+- 8, 3, 8, 11, 12, 12, 11, 10,
++ 8, 6, 8, 11, 12, 12, 11, 10,
+ 12, 11, 10, 12, 11, 10, 12, 11,
+- 9, 12, 16, 28, 11, 29, 29, 16,
++ 10, 12, 16, 28, 11, 29, 29, 16,
+ 16, 16, 16, 16, 29, 29, 16, 16,
+ 16, 16, 16, 29, 29, 16, 16, 16,
+ 16, 16, 29, 29, 16, 16, 16, 16,
+ 16, 29, 29, 29, 29, 28, 16, 29,
+ 29, 28, 16, 29, 29, 28, 16, 29,
+- 29, 28, 16, 29, 29, 28, 10, 7,
++ 29, 28, 16, 29, 29, 28, 10, 10,
+ 6, 2, 1, 2, 2, 1, 6, 11,
+- 8, 3, 8, 11, 12, 12, 11, 10,
++ 8, 6, 8, 11, 12, 12, 11, 10,
+ 12, 11, 10, 12, 11, 10, 12, 11,
+- 9, 12, 16, 28, 11, 29, 29, 16,
++ 10, 12, 16, 28, 11, 29, 29, 16,
+ 16, 16, 16, 16, 29, 29, 16, 16,
+ 16, 16, 16, 29, 29, 16, 16, 16,
+ 16, 16, 29, 29, 16, 16, 16, 16,
+ 11, 16, 29, 29, 28, 16, 29, 29,
+ 28, 16, 29, 29, 28, 16, 29, 29,
+- 28, 16, 29, 29, 28, 10, 7, 6,
++ 28, 16, 29, 29, 28, 10, 10, 6,
+ 2, 1, 2, 2, 1, 6, 11, 8,
+- 3, 8, 11, 12, 12, 11, 10, 12,
+- 11, 10, 12, 11, 10, 12, 11, 9,
++ 6, 8, 11, 12, 12, 11, 10, 12,
++ 11, 10, 12, 11, 10, 12, 11, 10,
+ 12, 16, 28, 11, 29, 29, 16, 16,
+ 16, 16, 16, 29, 29, 16, 16, 16,
+ 16, 16, 29, 29, 16, 16, 16, 16,
+ 16, 29, 29, 16, 16, 16, 16, 16,
+ 11, 29, 11, 29, 29, 28, 16, 29,
+ 29, 28, 16, 29, 29, 28, 16, 29,
+- 29, 28, 16, 29, 29, 28, 10, 7,
++ 29, 28, 16, 29, 29, 28, 10, 10,
+ 6, 2, 1, 2, 2, 1, 6, 11,
+- 8, 3, 8, 11, 12, 12, 11, 10,
++ 8, 6, 8, 11, 12, 12, 11, 10,
+ 12, 11, 10, 12, 11, 10, 12, 11,
+- 9, 12, 16, 28, 11, 29, 29, 16,
++ 10, 12, 16, 28, 11, 29, 29, 16,
+ 16, 16, 16, 16, 29, 29, 16, 16,
+ 16, 16, 16, 29, 29, 16, 16, 16,
+ 16, 16, 29, 29, 16, 16, 16, 16,
+- 16, 29, 31, 29, 31, 11, 16, 29,
+- 29, 28, 6, 2, 1, 2, 2, 1,
+- 6, 29, 29, 16, 12, 11, 10, 12,
+- 11, 10, 12, 11, 10, 12, 11, 7,
+- 11, 8, 3, 8, 11, 16, 8, 3,
++ 16, 29, 31, 29, 31, 11, 6, 2,
++ 1, 2, 2, 1, 6, 16, 29, 29,
++ 28, 29, 29, 16, 12, 11, 10, 12,
++ 11, 10, 12, 11, 10, 12, 11, 10,
++ 11, 8, 6, 8, 11, 16, 8, 6,
+ 6, 2, 1, 2, 2, 1, 6
+ };
+
+ static const short _indic_syllable_machine_index_offsets[] = {
+- 0, 17, 19, 23, 27, 29, 33, 37,
+- 39, 43, 47, 49, 53, 57, 59, 61,
+- 63, 65, 70, 72, 74, 79, 81, 83,
+- 88, 90, 92, 104, 116, 128, 140, 152,
+- 164, 176, 188, 200, 212, 229, 231, 235,
+- 239, 241, 245, 249, 251, 255, 259, 261,
+- 265, 269, 271, 273, 275, 277, 282, 284,
+- 286, 291, 293, 295, 300, 302, 304, 316,
+- 328, 340, 352, 364, 376, 388, 400, 412,
+- 424, 441, 443, 447, 451, 453, 457, 461,
+- 463, 467, 471, 473, 477, 481, 483, 485,
+- 487, 489, 494, 496, 498, 503, 505, 507,
+- 512, 514, 516, 528, 540, 552, 564, 576,
+- 588, 600, 612, 624, 641, 643, 647, 651,
+- 653, 657, 661, 663, 667, 671, 673, 677,
+- 681, 683, 685, 687, 689, 694, 696, 698,
+- 703, 705, 707, 712, 714, 716, 728, 740,
+- 752, 764, 776, 788, 800, 812, 824, 836,
+- 848, 860, 864, 868, 872, 876, 878, 882,
+- 886, 888, 892, 896, 898, 915, 917, 919,
+- 921, 923, 928, 930, 932, 937, 939, 941,
+- 946, 948, 950, 982, 1012, 1042, 1071, 1088,
+- 1118, 1148, 1177, 1194, 1224, 1254, 1283, 1300,
+- 1330, 1360, 1389, 1406, 1436, 1466, 1495, 1506,
+- 1514, 1521, 1524, 1526, 1529, 1532, 1534, 1541,
+- 1553, 1562, 1566, 1575, 1587, 1600, 1613, 1625,
+- 1636, 1649, 1661, 1672, 1685, 1697, 1708, 1721,
+- 1733, 1743, 1756, 1773, 1802, 1814, 1844, 1874,
+- 1891, 1908, 1925, 1942, 1959, 1989, 2019, 2036,
+- 2053, 2070, 2087, 2104, 2134, 2164, 2181, 2198,
+- 2215, 2232, 2249, 2279, 2309, 2326, 2343, 2360,
+- 2377, 2394, 2424, 2454, 2484, 2514, 2543, 2560,
+- 2590, 2620, 2649, 2666, 2696, 2726, 2755, 2772,
+- 2802, 2832, 2861, 2878, 2908, 2938, 2967, 2978,
+- 2986, 2993, 2996, 2998, 3001, 3004, 3006, 3013,
+- 3025, 3034, 3038, 3047, 3059, 3072, 3085, 3097,
+- 3108, 3121, 3133, 3144, 3157, 3169, 3180, 3193,
+- 3205, 3215, 3228, 3245, 3274, 3286, 3316, 3346,
+- 3363, 3380, 3397, 3414, 3431, 3461, 3491, 3508,
+- 3525, 3542, 3559, 3576, 3606, 3636, 3653, 3670,
+- 3687, 3704, 3721, 3751, 3781, 3798, 3815, 3832,
+- 3849, 3861, 3878, 3908, 3938, 3967, 3984, 4014,
+- 4044, 4073, 4090, 4120, 4150, 4179, 4196, 4226,
+- 4256, 4285, 4302, 4332, 4362, 4391, 4402, 4410,
+- 4417, 4420, 4422, 4425, 4428, 4430, 4437, 4449,
+- 4458, 4462, 4471, 4483, 4496, 4509, 4521, 4532,
+- 4545, 4557, 4568, 4581, 4593, 4604, 4617, 4629,
+- 4639, 4652, 4669, 4698, 4710, 4740, 4770, 4787,
+- 4804, 4821, 4838, 4855, 4885, 4915, 4932, 4949,
+- 4966, 4983, 5000, 5030, 5060, 5077, 5094, 5111,
+- 5128, 5145, 5175, 5205, 5222, 5239, 5256, 5273,
+- 5290, 5302, 5332, 5344, 5374, 5404, 5433, 5450,
+- 5480, 5510, 5539, 5556, 5586, 5616, 5645, 5662,
+- 5692, 5722, 5751, 5768, 5798, 5828, 5857, 5868,
+- 5876, 5883, 5886, 5888, 5891, 5894, 5896, 5903,
+- 5915, 5924, 5928, 5937, 5949, 5962, 5975, 5987,
+- 5998, 6011, 6023, 6034, 6047, 6059, 6070, 6083,
+- 6095, 6105, 6118, 6135, 6164, 6176, 6206, 6236,
+- 6253, 6270, 6287, 6304, 6321, 6351, 6381, 6398,
+- 6415, 6432, 6449, 6466, 6496, 6526, 6543, 6560,
+- 6577, 6594, 6611, 6641, 6671, 6688, 6705, 6722,
+- 6739, 6756, 6786, 6818, 6848, 6880, 6892, 6909,
+- 6939, 6969, 6998, 7005, 7008, 7010, 7013, 7016,
+- 7018, 7025, 7055, 7085, 7102, 7115, 7127, 7138,
+- 7151, 7163, 7174, 7187, 7199, 7210, 7223, 7235,
+- 7243, 7255, 7264, 7268, 7277, 7289, 7306, 7315,
+- 7319, 7326, 7329, 7331, 7334, 7337, 7339
++ 0, 2, 19, 26, 31, 35, 37, 42,
++ 46, 48, 53, 57, 59, 64, 68, 70,
++ 76, 78, 80, 86, 88, 90, 96, 98,
++ 100, 106, 108, 110, 122, 134, 146, 158,
++ 170, 182, 194, 206, 218, 230, 232, 249,
++ 256, 261, 265, 267, 272, 276, 278, 283,
++ 287, 289, 294, 298, 300, 306, 308, 310,
++ 316, 318, 320, 326, 328, 330, 336, 338,
++ 340, 352, 364, 376, 388, 400, 412, 424,
++ 436, 448, 460, 462, 479, 486, 491, 495,
++ 497, 502, 506, 508, 513, 517, 519, 524,
++ 528, 530, 536, 538, 540, 546, 548, 550,
++ 556, 558, 560, 566, 568, 570, 582, 594,
++ 606, 618, 630, 642, 654, 666, 678, 680,
++ 697, 704, 709, 713, 715, 720, 724, 726,
++ 731, 735, 737, 742, 746, 748, 754, 756,
++ 758, 764, 766, 768, 774, 776, 778, 784,
++ 786, 788, 800, 812, 824, 836, 848, 860,
++ 872, 884, 896, 908, 920, 925, 937, 949,
++ 954, 958, 963, 967, 969, 974, 978, 980,
++ 985, 989, 991, 993, 1010, 1017, 1023, 1025,
++ 1027, 1033, 1035, 1037, 1043, 1045, 1047, 1053,
++ 1055, 1057, 1059, 1091, 1121, 1151, 1180, 1197,
++ 1227, 1257, 1286, 1303, 1333, 1363, 1392, 1409,
++ 1439, 1469, 1498, 1515, 1545, 1575, 1604, 1615,
++ 1626, 1633, 1636, 1638, 1641, 1644, 1646, 1653,
++ 1665, 1674, 1681, 1690, 1702, 1715, 1728, 1740,
++ 1751, 1764, 1776, 1787, 1800, 1812, 1823, 1836,
++ 1848, 1859, 1872, 1889, 1918, 1930, 1960, 1990,
++ 2007, 2024, 2041, 2058, 2075, 2105, 2135, 2152,
++ 2169, 2186, 2203, 2220, 2250, 2280, 2297, 2314,
++ 2331, 2348, 2365, 2395, 2425, 2442, 2459, 2476,
++ 2493, 2510, 2540, 2570, 2600, 2630, 2659, 2676,
++ 2706, 2736, 2765, 2782, 2812, 2842, 2871, 2888,
++ 2918, 2948, 2977, 2994, 3024, 3054, 3083, 3094,
++ 3105, 3112, 3115, 3117, 3120, 3123, 3125, 3132,
++ 3144, 3153, 3160, 3169, 3181, 3194, 3207, 3219,
++ 3230, 3243, 3255, 3266, 3279, 3291, 3302, 3315,
++ 3327, 3338, 3351, 3368, 3397, 3409, 3439, 3469,
++ 3486, 3503, 3520, 3537, 3554, 3584, 3614, 3631,
++ 3648, 3665, 3682, 3699, 3729, 3759, 3776, 3793,
++ 3810, 3827, 3844, 3874, 3904, 3921, 3938, 3955,
++ 3972, 3984, 4001, 4031, 4061, 4090, 4107, 4137,
++ 4167, 4196, 4213, 4243, 4273, 4302, 4319, 4349,
++ 4379, 4408, 4425, 4455, 4485, 4514, 4525, 4536,
++ 4543, 4546, 4548, 4551, 4554, 4556, 4563, 4575,
++ 4584, 4591, 4600, 4612, 4625, 4638, 4650, 4661,
++ 4674, 4686, 4697, 4710, 4722, 4733, 4746, 4758,
++ 4769, 4782, 4799, 4828, 4840, 4870, 4900, 4917,
++ 4934, 4951, 4968, 4985, 5015, 5045, 5062, 5079,
++ 5096, 5113, 5130, 5160, 5190, 5207, 5224, 5241,
++ 5258, 5275, 5305, 5335, 5352, 5369, 5386, 5403,
++ 5420, 5432, 5462, 5474, 5504, 5534, 5563, 5580,
++ 5610, 5640, 5669, 5686, 5716, 5746, 5775, 5792,
++ 5822, 5852, 5881, 5898, 5928, 5958, 5987, 5998,
++ 6009, 6016, 6019, 6021, 6024, 6027, 6029, 6036,
++ 6048, 6057, 6064, 6073, 6085, 6098, 6111, 6123,
++ 6134, 6147, 6159, 6170, 6183, 6195, 6206, 6219,
++ 6231, 6242, 6255, 6272, 6301, 6313, 6343, 6373,
++ 6390, 6407, 6424, 6441, 6458, 6488, 6518, 6535,
++ 6552, 6569, 6586, 6603, 6633, 6663, 6680, 6697,
++ 6714, 6731, 6748, 6778, 6808, 6825, 6842, 6859,
++ 6876, 6893, 6923, 6955, 6985, 7017, 7029, 7036,
++ 7039, 7041, 7044, 7047, 7049, 7056, 7073, 7103,
++ 7133, 7162, 7192, 7222, 7239, 7252, 7264, 7275,
++ 7288, 7300, 7311, 7324, 7336, 7347, 7360, 7372,
++ 7383, 7395, 7404, 7411, 7420, 7432, 7449, 7458,
++ 7465, 7472, 7475, 7477, 7480, 7483, 7485
+ };
+
+ static const short _indic_syllable_machine_indicies[] = {
+- 1, 2, 0, 0, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 1,
+- 0, 3, 0, 4, 4, 5, 0, 6,
+- 6, 5, 0, 5, 0, 7, 7, 8,
+- 0, 9, 9, 8, 0, 8, 0, 10,
+- 10, 11, 0, 12, 12, 11, 0, 11,
+- 0, 13, 13, 14, 0, 15, 15, 14,
+- 0, 14, 0, 16, 0, 17, 0, 18,
+- 0, 19, 13, 13, 14, 0, 20, 0,
+- 21, 0, 22, 10, 10, 11, 0, 23,
+- 0, 24, 0, 25, 7, 7, 8, 0,
+- 26, 0, 27, 0, 28, 4, 4, 5,
+- 0, 0, 0, 0, 0, 0, 28, 0,
+- 28, 4, 4, 5, 0, 0, 0, 0,
+- 0, 29, 28, 0, 30, 4, 4, 5,
+- 0, 0, 0, 0, 0, 0, 30, 0,
+- 30, 4, 4, 5, 0, 0, 0, 0,
+- 0, 31, 30, 0, 32, 4, 4, 5,
+- 0, 0, 0, 0, 0, 0, 32, 0,
+- 32, 4, 4, 5, 0, 0, 0, 0,
+- 0, 33, 32, 0, 34, 4, 4, 5,
+- 0, 0, 0, 0, 0, 0, 34, 0,
+- 34, 4, 4, 5, 0, 0, 0, 0,
+- 0, 35, 34, 0, 36, 4, 4, 5,
+- 0, 0, 0, 0, 0, 0, 36, 0,
+- 36, 4, 4, 5, 0, 0, 0, 0,
+- 0, 37, 36, 0, 39, 40, 38, 38,
+- 38, 38, 38, 38, 38, 38, 38, 38,
+- 38, 38, 38, 39, 38, 41, 38, 42,
+- 42, 43, 38, 44, 44, 43, 38, 43,
+- 38, 45, 45, 46, 38, 47, 47, 46,
+- 38, 46, 38, 48, 48, 49, 38, 50,
+- 50, 49, 38, 49, 38, 51, 51, 52,
+- 38, 53, 53, 52, 38, 52, 38, 54,
+- 38, 55, 38, 56, 38, 57, 51, 51,
+- 52, 38, 58, 38, 59, 38, 60, 48,
+- 48, 49, 38, 61, 38, 62, 38, 63,
+- 45, 45, 46, 38, 64, 38, 65, 38,
+- 66, 42, 42, 43, 38, 38, 38, 38,
+- 38, 38, 66, 38, 66, 42, 42, 43,
+- 38, 38, 38, 38, 38, 67, 66, 38,
+- 68, 42, 42, 43, 38, 38, 38, 38,
+- 38, 38, 68, 38, 68, 42, 42, 43,
+- 38, 38, 38, 38, 38, 69, 68, 38,
+- 70, 42, 42, 43, 38, 38, 38, 38,
+- 38, 38, 70, 38, 70, 42, 42, 43,
+- 38, 38, 38, 38, 38, 71, 70, 38,
+- 72, 42, 42, 43, 38, 38, 38, 38,
+- 38, 38, 72, 38, 72, 42, 42, 43,
+- 38, 38, 38, 38, 38, 73, 72, 38,
+- 74, 42, 42, 43, 38, 38, 38, 38,
+- 38, 38, 74, 38, 74, 42, 42, 43,
+- 38, 38, 38, 38, 38, 75, 74, 38,
+- 77, 78, 76, 76, 76, 76, 76, 76,
+- 76, 76, 76, 76, 76, 76, 76, 77,
+- 76, 79, 76, 80, 80, 81, 76, 83,
+- 83, 81, 82, 81, 82, 84, 84, 85,
+- 76, 86, 86, 85, 76, 85, 76, 87,
+- 87, 88, 76, 89, 89, 88, 76, 88,
+- 76, 90, 90, 91, 76, 92, 92, 91,
+- 76, 91, 76, 93, 76, 94, 76, 95,
+- 76, 96, 90, 90, 91, 76, 97, 76,
+- 98, 76, 99, 87, 87, 88, 76, 100,
+- 76, 101, 76, 102, 84, 84, 85, 76,
+- 103, 76, 104, 76, 105, 80, 80, 81,
+- 76, 76, 76, 76, 76, 76, 105, 76,
+- 105, 80, 80, 81, 76, 76, 76, 76,
+- 76, 106, 105, 76, 107, 80, 80, 81,
+- 76, 76, 76, 76, 76, 76, 107, 76,
+- 107, 80, 80, 81, 76, 76, 76, 76,
+- 76, 108, 107, 76, 109, 80, 80, 81,
+- 76, 76, 76, 76, 76, 76, 109, 76,
+- 109, 80, 80, 81, 76, 76, 76, 76,
+- 76, 110, 109, 76, 111, 80, 80, 81,
+- 82, 82, 82, 82, 82, 82, 111, 82,
+- 111, 80, 80, 81, 76, 76, 76, 76,
+- 76, 112, 111, 76, 113, 80, 80, 81,
+- 76, 76, 76, 76, 76, 76, 113, 76,
+- 115, 116, 114, 114, 114, 114, 114, 114,
+- 114, 114, 114, 114, 114, 114, 114, 115,
+- 114, 117, 114, 118, 118, 119, 114, 120,
+- 120, 119, 114, 119, 114, 121, 121, 122,
+- 114, 123, 123, 122, 114, 122, 114, 124,
+- 124, 125, 114, 126, 126, 125, 114, 125,
+- 114, 127, 127, 128, 114, 129, 129, 128,
+- 114, 128, 114, 130, 114, 131, 114, 132,
+- 114, 133, 127, 127, 128, 114, 134, 114,
+- 135, 114, 136, 124, 124, 125, 114, 137,
+- 114, 138, 114, 139, 121, 121, 122, 114,
+- 140, 114, 141, 114, 142, 118, 118, 119,
+- 114, 114, 114, 114, 114, 114, 142, 114,
+- 142, 118, 118, 119, 114, 114, 114, 114,
+- 114, 143, 142, 114, 144, 118, 118, 119,
+- 114, 114, 114, 114, 114, 114, 144, 114,
+- 144, 118, 118, 119, 114, 114, 114, 114,
+- 114, 145, 144, 114, 146, 118, 118, 119,
+- 114, 114, 114, 114, 114, 114, 146, 114,
+- 146, 118, 118, 119, 114, 114, 114, 114,
+- 114, 147, 146, 114, 148, 118, 118, 119,
+- 114, 114, 114, 114, 114, 114, 148, 114,
+- 148, 118, 118, 119, 114, 114, 114, 114,
+- 114, 149, 148, 114, 150, 118, 118, 119,
+- 114, 114, 114, 114, 114, 114, 150, 114,
+- 150, 118, 118, 119, 114, 114, 114, 114,
+- 114, 151, 150, 114, 113, 80, 80, 81,
+- 76, 76, 76, 76, 76, 152, 113, 76,
+- 111, 80, 80, 81, 0, 0, 0, 0,
+- 0, 153, 111, 0, 154, 154, 155, 0,
+- 6, 6, 155, 0, 156, 156, 157, 0,
+- 158, 158, 157, 0, 157, 0, 159, 159,
+- 160, 0, 161, 161, 160, 0, 160, 0,
+- 162, 162, 163, 0, 164, 164, 163, 0,
+- 163, 0, 165, 166, 0, 0, 0, 0,
+- 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 165, 0, 167, 0, 168, 0, 169,
+- 0, 170, 0, 171, 162, 162, 163, 0,
+- 172, 0, 173, 0, 174, 159, 159, 160,
+- 0, 175, 0, 176, 0, 177, 156, 156,
+- 157, 0, 178, 0, 179, 0, 181, 182,
+- 183, 184, 185, 186, 81, 187, 188, 189,
+- 190, 190, 152, 191, 192, 193, 194, 195,
+- 180, 180, 180, 180, 180, 180, 180, 180,
+- 180, 180, 180, 180, 196, 180, 198, 199,
+- 200, 201, 5, 202, 203, 204, 197, 197,
+- 37, 205, 197, 197, 206, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 207, 197, 208, 199, 209, 209,
+- 5, 202, 203, 204, 197, 197, 197, 205,
+- 197, 197, 206, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 207, 197, 199, 209, 209, 5, 202, 203,
+- 204, 197, 197, 197, 205, 197, 197, 206,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 207, 197, 210,
+- 197, 197, 197, 18, 211, 197, 202, 203,
+- 204, 197, 197, 197, 212, 197, 210, 197,
+- 213, 214, 215, 216, 5, 202, 203, 204,
+- 197, 197, 35, 217, 197, 197, 206, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 207, 197, 218, 214,
+- 219, 219, 5, 202, 203, 204, 197, 197,
+- 197, 217, 197, 197, 206, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 207, 197, 214, 219, 219, 5,
+- 202, 203, 204, 197, 197, 197, 217, 197,
+- 197, 206, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 207,
+- 197, 220, 197, 197, 197, 18, 221, 197,
+- 202, 203, 204, 197, 197, 197, 212, 197,
+- 220, 197, 222, 223, 224, 225, 5, 202,
+- 203, 204, 197, 197, 33, 226, 197, 197,
+- 206, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 207, 197,
+- 227, 223, 228, 228, 5, 202, 203, 204,
+- 197, 197, 197, 226, 197, 197, 206, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 207, 197, 223, 228,
+- 228, 5, 202, 203, 204, 197, 197, 197,
+- 226, 197, 197, 206, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 207, 197, 229, 197, 197, 197, 18,
+- 230, 197, 202, 203, 204, 197, 197, 197,
+- 212, 197, 229, 197, 231, 232, 233, 234,
+- 5, 202, 203, 204, 197, 197, 31, 235,
+- 197, 197, 206, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 207, 197, 236, 232, 237, 237, 5, 202,
+- 203, 204, 197, 197, 197, 235, 197, 197,
+- 206, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 207, 197,
+- 232, 237, 237, 5, 202, 203, 204, 197,
+- 197, 197, 235, 197, 197, 206, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 207, 197, 238, 197, 197,
+- 197, 18, 239, 197, 202, 203, 204, 197,
+- 197, 197, 212, 197, 238, 197, 240, 241,
+- 242, 243, 5, 202, 203, 204, 197, 197,
+- 29, 244, 197, 197, 206, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 207, 197, 245, 241, 246, 246,
+- 5, 202, 203, 204, 197, 197, 197, 244,
+- 197, 197, 206, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 207, 197, 241, 246, 246, 5, 202, 203,
+- 204, 197, 197, 197, 244, 197, 197, 206,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 207, 197, 18,
+- 247, 197, 202, 203, 204, 197, 197, 197,
+- 212, 197, 202, 203, 204, 197, 197, 197,
+- 212, 197, 248, 197, 197, 249, 203, 204,
+- 197, 203, 204, 197, 250, 197, 203, 251,
+- 197, 203, 252, 197, 203, 197, 248, 197,
+- 197, 197, 203, 204, 197, 253, 197, 254,
+- 255, 197, 202, 203, 204, 197, 197, 3,
+- 197, 2, 197, 197, 197, 197, 202, 203,
+- 204, 197, 202, 203, 204, 197, 253, 197,
+- 197, 197, 197, 202, 203, 204, 197, 253,
+- 197, 254, 197, 197, 202, 203, 204, 197,
+- 197, 3, 197, 18, 197, 256, 256, 5,
+- 202, 203, 204, 197, 197, 197, 212, 197,
+- 257, 27, 258, 259, 8, 202, 203, 204,
+- 197, 197, 197, 212, 197, 27, 258, 259,
+- 8, 202, 203, 204, 197, 197, 197, 212,
+- 197, 258, 258, 8, 202, 203, 204, 197,
+- 197, 197, 212, 197, 260, 24, 261, 262,
+- 11, 202, 203, 204, 197, 197, 197, 212,
+- 197, 24, 261, 262, 11, 202, 203, 204,
+- 197, 197, 197, 212, 197, 261, 261, 11,
+- 202, 203, 204, 197, 197, 197, 212, 197,
+- 263, 21, 264, 265, 14, 202, 203, 204,
+- 197, 197, 197, 212, 197, 21, 264, 265,
+- 14, 202, 203, 204, 197, 197, 197, 212,
+- 197, 264, 264, 14, 202, 203, 204, 197,
+- 197, 197, 212, 197, 266, 18, 197, 267,
+- 197, 202, 203, 204, 197, 197, 197, 212,
+- 197, 18, 197, 267, 197, 202, 203, 204,
+- 197, 197, 197, 212, 197, 268, 197, 202,
+- 203, 204, 197, 197, 197, 212, 197, 18,
+- 197, 197, 197, 197, 202, 203, 204, 197,
+- 197, 197, 212, 197, 1, 2, 197, 197,
+- 18, 247, 197, 202, 203, 204, 197, 197,
+- 197, 212, 197, 1, 197, 241, 246, 246,
+- 5, 202, 203, 204, 197, 197, 197, 244,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 207, 197, 241, 246, 246, 5, 202, 203,
+- 204, 197, 197, 197, 244, 197, 240, 241,
+- 246, 246, 5, 202, 203, 204, 197, 197,
+- 197, 244, 197, 197, 206, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 207, 197, 240, 241, 242, 246,
+- 5, 202, 203, 204, 197, 197, 29, 244,
+- 197, 197, 206, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 207, 197, 238, 197, 269, 197, 256, 256,
+- 5, 202, 203, 204, 197, 197, 197, 212,
+- 197, 238, 197, 238, 197, 197, 197, 197,
+- 197, 197, 202, 203, 204, 197, 197, 197,
+- 212, 197, 238, 197, 238, 197, 197, 197,
+- 197, 270, 197, 202, 203, 204, 197, 197,
+- 197, 212, 197, 238, 197, 238, 197, 269,
+- 197, 197, 197, 197, 202, 203, 204, 197,
+- 197, 197, 212, 197, 238, 197, 238, 2,
+- 197, 197, 18, 239, 197, 202, 203, 204,
+- 197, 197, 197, 212, 197, 238, 197, 231,
+- 232, 237, 237, 5, 202, 203, 204, 197,
+- 197, 197, 235, 197, 197, 206, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 207, 197, 231, 232, 233,
+- 237, 5, 202, 203, 204, 197, 197, 31,
+- 235, 197, 197, 206, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 207, 197, 229, 197, 271, 197, 256,
+- 256, 5, 202, 203, 204, 197, 197, 197,
+- 212, 197, 229, 197, 229, 197, 197, 197,
+- 197, 197, 197, 202, 203, 204, 197, 197,
+- 197, 212, 197, 229, 197, 229, 197, 197,
+- 197, 197, 272, 197, 202, 203, 204, 197,
+- 197, 197, 212, 197, 229, 197, 229, 197,
+- 271, 197, 197, 197, 197, 202, 203, 204,
+- 197, 197, 197, 212, 197, 229, 197, 229,
+- 2, 197, 197, 18, 230, 197, 202, 203,
+- 204, 197, 197, 197, 212, 197, 229, 197,
+- 222, 223, 228, 228, 5, 202, 203, 204,
+- 197, 197, 197, 226, 197, 197, 206, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 207, 197, 222, 223,
+- 224, 228, 5, 202, 203, 204, 197, 197,
+- 33, 226, 197, 197, 206, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 207, 197, 220, 197, 273, 197,
+- 256, 256, 5, 202, 203, 204, 197, 197,
+- 197, 212, 197, 220, 197, 220, 197, 197,
+- 197, 197, 197, 197, 202, 203, 204, 197,
+- 197, 197, 212, 197, 220, 197, 220, 197,
+- 197, 197, 197, 274, 197, 202, 203, 204,
+- 197, 197, 197, 212, 197, 220, 197, 220,
+- 197, 273, 197, 197, 197, 197, 202, 203,
+- 204, 197, 197, 197, 212, 197, 220, 197,
+- 220, 2, 197, 197, 18, 221, 197, 202,
+- 203, 204, 197, 197, 197, 212, 197, 220,
+- 197, 213, 214, 219, 219, 5, 202, 203,
+- 204, 197, 197, 197, 217, 197, 197, 206,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 207, 197, 213,
+- 214, 215, 219, 5, 202, 203, 204, 197,
+- 197, 35, 217, 197, 197, 206, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 207, 197, 210, 197, 275,
+- 197, 256, 256, 5, 202, 203, 204, 197,
+- 197, 197, 212, 197, 210, 197, 210, 197,
+- 197, 197, 197, 197, 197, 202, 203, 204,
+- 197, 197, 197, 212, 197, 210, 197, 210,
+- 197, 197, 197, 197, 276, 197, 202, 203,
+- 204, 197, 197, 197, 212, 197, 210, 197,
+- 210, 197, 275, 197, 197, 197, 197, 202,
+- 203, 204, 197, 197, 197, 212, 197, 210,
+- 197, 210, 2, 197, 197, 18, 211, 197,
+- 202, 203, 204, 197, 197, 197, 212, 197,
+- 210, 197, 198, 199, 209, 209, 5, 202,
+- 203, 204, 197, 197, 197, 205, 197, 197,
+- 206, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 207, 197,
+- 198, 199, 200, 209, 5, 202, 203, 204,
+- 197, 197, 37, 205, 197, 197, 206, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 207, 197, 278, 279,
+- 280, 281, 43, 282, 283, 284, 277, 277,
+- 75, 285, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 288, 279, 289, 281,
+- 43, 282, 283, 284, 277, 277, 277, 285,
+- 277, 277, 286, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 287, 277, 279, 289, 281, 43, 282, 283,
+- 284, 277, 277, 277, 285, 277, 277, 286,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 287, 277, 290,
+- 277, 277, 277, 56, 291, 277, 282, 283,
+- 284, 277, 277, 277, 292, 277, 290, 277,
+- 293, 294, 295, 296, 43, 282, 283, 284,
+- 277, 277, 73, 297, 277, 277, 286, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 287, 277, 298, 294,
+- 299, 299, 43, 282, 283, 284, 277, 277,
+- 277, 297, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 294, 299, 299, 43,
+- 282, 283, 284, 277, 277, 277, 297, 277,
+- 277, 286, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 287,
+- 277, 300, 277, 277, 277, 56, 301, 277,
+- 282, 283, 284, 277, 277, 277, 292, 277,
+- 300, 277, 302, 303, 304, 305, 43, 282,
+- 283, 284, 277, 277, 71, 306, 277, 277,
+- 286, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 287, 277,
+- 307, 303, 308, 308, 43, 282, 283, 284,
+- 277, 277, 277, 306, 277, 277, 286, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 287, 277, 303, 308,
+- 308, 43, 282, 283, 284, 277, 277, 277,
+- 306, 277, 277, 286, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 287, 277, 309, 277, 277, 277, 56,
+- 310, 277, 282, 283, 284, 277, 277, 277,
+- 292, 277, 309, 277, 311, 312, 313, 314,
+- 43, 282, 283, 284, 277, 277, 69, 315,
+- 277, 277, 286, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 287, 277, 316, 312, 317, 317, 43, 282,
+- 283, 284, 277, 277, 277, 315, 277, 277,
+- 286, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 287, 277,
+- 312, 317, 317, 43, 282, 283, 284, 277,
+- 277, 277, 315, 277, 277, 286, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 287, 277, 318, 277, 277,
+- 277, 56, 319, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 318, 277, 320, 321,
+- 322, 323, 43, 282, 283, 284, 277, 277,
+- 67, 324, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 325, 321, 326, 326,
+- 43, 282, 283, 284, 277, 277, 277, 324,
+- 277, 277, 286, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 287, 277, 321, 326, 326, 43, 282, 283,
+- 284, 277, 277, 277, 324, 277, 277, 286,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 287, 277, 56,
+- 327, 277, 282, 283, 284, 277, 277, 277,
+- 292, 277, 282, 283, 284, 277, 277, 277,
+- 292, 277, 328, 277, 277, 329, 283, 284,
+- 277, 283, 284, 277, 330, 277, 283, 331,
+- 277, 283, 332, 277, 283, 277, 328, 277,
+- 277, 277, 283, 284, 277, 333, 277, 334,
+- 335, 277, 282, 283, 284, 277, 277, 41,
+- 277, 40, 277, 277, 277, 277, 282, 283,
+- 284, 277, 282, 283, 284, 277, 333, 277,
+- 277, 277, 277, 282, 283, 284, 277, 333,
+- 277, 334, 277, 277, 282, 283, 284, 277,
+- 277, 41, 277, 56, 277, 336, 336, 43,
+- 282, 283, 284, 277, 277, 277, 292, 277,
+- 337, 65, 338, 339, 46, 282, 283, 284,
+- 277, 277, 277, 292, 277, 65, 338, 339,
+- 46, 282, 283, 284, 277, 277, 277, 292,
+- 277, 338, 338, 46, 282, 283, 284, 277,
+- 277, 277, 292, 277, 340, 62, 341, 342,
+- 49, 282, 283, 284, 277, 277, 277, 292,
+- 277, 62, 341, 342, 49, 282, 283, 284,
+- 277, 277, 277, 292, 277, 341, 341, 49,
+- 282, 283, 284, 277, 277, 277, 292, 277,
+- 343, 59, 344, 345, 52, 282, 283, 284,
+- 277, 277, 277, 292, 277, 59, 344, 345,
+- 52, 282, 283, 284, 277, 277, 277, 292,
+- 277, 344, 344, 52, 282, 283, 284, 277,
+- 277, 277, 292, 277, 346, 56, 277, 347,
+- 277, 282, 283, 284, 277, 277, 277, 292,
+- 277, 56, 277, 347, 277, 282, 283, 284,
+- 277, 277, 277, 292, 277, 348, 277, 282,
+- 283, 284, 277, 277, 277, 292, 277, 56,
+- 277, 277, 277, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 39, 40, 277, 277,
+- 56, 327, 277, 282, 283, 284, 277, 277,
+- 277, 292, 277, 39, 277, 321, 326, 326,
+- 43, 282, 283, 284, 277, 277, 277, 324,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 287, 277, 321, 326, 326, 43, 282, 283,
+- 284, 277, 277, 277, 324, 277, 320, 321,
+- 326, 326, 43, 282, 283, 284, 277, 277,
+- 277, 324, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 320, 321, 322, 326,
+- 43, 282, 283, 284, 277, 277, 67, 324,
+- 277, 277, 286, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 287, 277, 318, 277, 349, 277, 336, 336,
+- 43, 282, 283, 284, 277, 277, 277, 292,
+- 277, 318, 277, 318, 277, 277, 277, 277,
+- 277, 277, 282, 283, 284, 277, 277, 277,
+- 292, 277, 318, 277, 318, 277, 277, 277,
+- 277, 350, 277, 282, 283, 284, 277, 277,
+- 277, 292, 277, 318, 277, 318, 277, 349,
+- 277, 277, 277, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 318, 277, 318, 40,
+- 277, 277, 56, 319, 277, 282, 283, 284,
+- 277, 277, 277, 292, 277, 318, 277, 311,
+- 312, 317, 317, 43, 282, 283, 284, 277,
+- 277, 277, 315, 277, 277, 286, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 287, 277, 311, 312, 313,
+- 317, 43, 282, 283, 284, 277, 277, 69,
+- 315, 277, 277, 286, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 287, 277, 309, 277, 351, 277, 336,
+- 336, 43, 282, 283, 284, 277, 277, 277,
+- 292, 277, 309, 277, 309, 277, 277, 277,
+- 277, 277, 277, 282, 283, 284, 277, 277,
+- 277, 292, 277, 309, 277, 309, 277, 277,
+- 277, 277, 352, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 309, 277, 309, 277,
+- 351, 277, 277, 277, 277, 282, 283, 284,
+- 277, 277, 277, 292, 277, 309, 277, 309,
+- 40, 277, 277, 56, 310, 277, 282, 283,
+- 284, 277, 277, 277, 292, 277, 309, 277,
+- 302, 303, 308, 308, 43, 282, 283, 284,
+- 277, 277, 277, 306, 277, 277, 286, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 287, 277, 302, 303,
+- 304, 308, 43, 282, 283, 284, 277, 277,
+- 71, 306, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 300, 277, 353, 277,
+- 336, 336, 43, 282, 283, 284, 277, 277,
+- 277, 292, 277, 300, 277, 300, 277, 277,
+- 277, 277, 277, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 300, 277, 300, 277,
+- 277, 277, 277, 354, 277, 282, 283, 284,
+- 277, 277, 277, 292, 277, 300, 277, 300,
+- 277, 353, 277, 277, 277, 277, 282, 283,
+- 284, 277, 277, 277, 292, 277, 300, 277,
+- 300, 40, 277, 277, 56, 301, 277, 282,
+- 283, 284, 277, 277, 277, 292, 277, 300,
+- 277, 293, 294, 299, 299, 43, 282, 283,
+- 284, 277, 277, 277, 297, 277, 277, 286,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 277, 277, 287, 277, 293,
+- 294, 295, 299, 43, 282, 283, 284, 277,
+- 277, 73, 297, 277, 277, 286, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 277, 287, 277, 290, 277, 355,
+- 277, 336, 336, 43, 282, 283, 284, 277,
+- 277, 277, 292, 277, 290, 277, 290, 277,
+- 277, 277, 277, 277, 277, 282, 283, 284,
+- 277, 277, 277, 292, 277, 290, 277, 290,
+- 277, 277, 277, 277, 356, 277, 282, 283,
+- 284, 277, 277, 277, 292, 277, 290, 277,
+- 290, 277, 355, 277, 277, 277, 277, 282,
+- 283, 284, 277, 277, 277, 292, 277, 290,
+- 277, 74, 42, 42, 43, 277, 277, 277,
+- 277, 277, 277, 74, 277, 290, 40, 277,
+- 277, 56, 291, 277, 282, 283, 284, 277,
+- 277, 277, 292, 277, 290, 277, 278, 279,
+- 289, 281, 43, 282, 283, 284, 277, 277,
+- 277, 285, 277, 277, 286, 277, 277, 277,
+- 277, 277, 277, 277, 277, 277, 277, 277,
+- 277, 277, 287, 277, 358, 184, 359, 359,
+- 81, 187, 188, 189, 357, 357, 357, 191,
+- 357, 357, 194, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 184, 359, 359, 81, 187, 188,
+- 189, 357, 357, 357, 191, 357, 357, 194,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 196, 357, 360,
+- 357, 357, 357, 95, 361, 357, 187, 188,
+- 189, 357, 357, 357, 362, 357, 360, 357,
+- 363, 364, 365, 366, 81, 187, 188, 189,
+- 357, 357, 112, 367, 357, 357, 194, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 196, 357, 368, 364,
+- 369, 369, 81, 187, 188, 189, 357, 357,
+- 357, 367, 357, 357, 194, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 196, 357, 364, 369, 369, 81,
+- 187, 188, 189, 357, 357, 357, 367, 357,
+- 357, 194, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 196,
+- 357, 370, 357, 357, 357, 95, 371, 357,
+- 187, 188, 189, 357, 357, 357, 362, 357,
+- 370, 357, 372, 373, 374, 375, 81, 187,
+- 188, 189, 357, 357, 110, 376, 357, 357,
+- 194, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 196, 357,
+- 377, 373, 378, 378, 81, 187, 188, 189,
+- 357, 357, 357, 376, 357, 357, 194, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 196, 357, 373, 378,
+- 378, 81, 187, 188, 189, 357, 357, 357,
+- 376, 357, 357, 194, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 196, 357, 379, 357, 357, 357, 95,
+- 380, 357, 187, 188, 189, 357, 357, 357,
+- 362, 357, 379, 357, 381, 382, 383, 384,
+- 81, 187, 188, 189, 357, 357, 108, 385,
+- 357, 357, 194, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 386, 382, 387, 387, 81, 187,
+- 188, 189, 357, 357, 357, 385, 357, 357,
+- 194, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 196, 357,
+- 382, 387, 387, 81, 187, 188, 189, 357,
+- 357, 357, 385, 357, 357, 194, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 196, 357, 388, 357, 357,
+- 357, 95, 389, 357, 187, 188, 189, 357,
+- 357, 357, 362, 357, 388, 357, 390, 391,
+- 392, 393, 81, 187, 188, 189, 357, 357,
+- 106, 394, 357, 357, 194, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 196, 357, 395, 391, 396, 396,
+- 81, 187, 188, 189, 357, 357, 357, 394,
+- 357, 357, 194, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 391, 396, 396, 81, 187, 188,
+- 189, 357, 357, 357, 394, 357, 357, 194,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 196, 357, 95,
+- 397, 357, 187, 188, 189, 357, 357, 357,
+- 362, 357, 187, 188, 189, 357, 357, 357,
+- 362, 357, 398, 357, 357, 399, 188, 189,
+- 357, 188, 189, 357, 400, 357, 188, 401,
+- 357, 188, 402, 357, 188, 357, 398, 357,
+- 357, 357, 188, 189, 357, 403, 357, 404,
+- 405, 357, 187, 188, 189, 357, 357, 79,
+- 357, 78, 357, 357, 357, 357, 187, 188,
+- 189, 357, 187, 188, 189, 357, 403, 357,
+- 357, 357, 357, 187, 188, 189, 357, 403,
+- 357, 404, 357, 357, 187, 188, 189, 357,
+- 357, 79, 357, 95, 357, 406, 406, 81,
+- 187, 188, 189, 357, 357, 357, 362, 357,
+- 407, 104, 408, 409, 85, 187, 188, 189,
+- 357, 357, 357, 362, 357, 104, 408, 409,
+- 85, 187, 188, 189, 357, 357, 357, 362,
+- 357, 408, 408, 85, 187, 188, 189, 357,
+- 357, 357, 362, 357, 410, 101, 411, 412,
+- 88, 187, 188, 189, 357, 357, 357, 362,
+- 357, 101, 411, 412, 88, 187, 188, 189,
+- 357, 357, 357, 362, 357, 411, 411, 88,
+- 187, 188, 189, 357, 357, 357, 362, 357,
+- 413, 98, 414, 415, 91, 187, 188, 189,
+- 357, 357, 357, 362, 357, 98, 414, 415,
+- 91, 187, 188, 189, 357, 357, 357, 362,
+- 357, 414, 414, 91, 187, 188, 189, 357,
+- 357, 357, 362, 357, 416, 95, 357, 417,
+- 357, 187, 188, 189, 357, 357, 357, 362,
+- 357, 95, 357, 417, 357, 187, 188, 189,
+- 357, 357, 357, 362, 357, 418, 357, 187,
+- 188, 189, 357, 357, 357, 362, 357, 95,
+- 357, 357, 357, 357, 187, 188, 189, 357,
+- 357, 357, 362, 357, 77, 78, 357, 357,
+- 95, 397, 357, 187, 188, 189, 357, 357,
+- 357, 362, 357, 77, 357, 391, 396, 396,
+- 81, 187, 188, 189, 357, 357, 357, 394,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 391, 396, 396, 81, 187, 188,
+- 189, 357, 357, 357, 394, 357, 390, 391,
+- 396, 396, 81, 187, 188, 189, 357, 357,
+- 357, 394, 357, 357, 194, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 196, 357, 390, 391, 392, 396,
+- 81, 187, 188, 189, 357, 357, 106, 394,
+- 357, 357, 194, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 388, 357, 419, 357, 406, 406,
+- 81, 187, 188, 189, 357, 357, 357, 362,
+- 357, 388, 357, 388, 357, 357, 357, 357,
+- 357, 357, 187, 188, 189, 357, 357, 357,
+- 362, 357, 388, 357, 388, 357, 357, 357,
+- 357, 420, 357, 187, 188, 189, 357, 357,
+- 357, 362, 357, 388, 357, 388, 357, 419,
+- 357, 357, 357, 357, 187, 188, 189, 357,
+- 357, 357, 362, 357, 388, 357, 388, 78,
+- 357, 357, 95, 389, 357, 187, 188, 189,
+- 357, 357, 357, 362, 357, 388, 357, 381,
+- 382, 387, 387, 81, 187, 188, 189, 357,
+- 357, 357, 385, 357, 357, 194, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 196, 357, 381, 382, 383,
+- 387, 81, 187, 188, 189, 357, 357, 108,
+- 385, 357, 357, 194, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 196, 357, 379, 357, 421, 357, 406,
+- 406, 81, 187, 188, 189, 357, 357, 357,
+- 362, 357, 379, 357, 379, 357, 357, 357,
+- 357, 357, 357, 187, 188, 189, 357, 357,
+- 357, 362, 357, 379, 357, 379, 357, 357,
+- 357, 357, 422, 357, 187, 188, 189, 357,
+- 357, 357, 362, 357, 379, 357, 379, 357,
+- 421, 357, 357, 357, 357, 187, 188, 189,
+- 357, 357, 357, 362, 357, 379, 357, 379,
+- 78, 357, 357, 95, 380, 357, 187, 188,
+- 189, 357, 357, 357, 362, 357, 379, 357,
+- 372, 373, 378, 378, 81, 187, 188, 189,
+- 357, 357, 357, 376, 357, 357, 194, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 196, 357, 372, 373,
+- 374, 378, 81, 187, 188, 189, 357, 357,
+- 110, 376, 357, 357, 194, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 196, 357, 370, 357, 423, 357,
+- 406, 406, 81, 187, 188, 189, 357, 357,
+- 357, 362, 357, 370, 357, 370, 357, 357,
+- 357, 357, 357, 357, 187, 188, 189, 357,
+- 357, 357, 362, 357, 370, 357, 370, 357,
+- 357, 357, 357, 424, 357, 187, 188, 189,
+- 357, 357, 357, 362, 357, 370, 357, 370,
+- 357, 423, 357, 357, 357, 357, 187, 188,
+- 189, 357, 357, 357, 362, 357, 370, 357,
+- 370, 78, 357, 357, 95, 371, 357, 187,
+- 188, 189, 357, 357, 357, 362, 357, 370,
+- 357, 363, 364, 369, 369, 81, 187, 188,
+- 189, 357, 357, 357, 367, 357, 357, 194,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 196, 357, 363,
+- 364, 365, 369, 81, 187, 188, 189, 357,
+- 357, 112, 367, 357, 357, 194, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 357, 196, 357, 360, 357, 425,
+- 357, 406, 406, 81, 187, 188, 189, 357,
+- 357, 357, 362, 357, 360, 357, 360, 357,
+- 357, 357, 357, 357, 357, 187, 188, 189,
+- 357, 357, 357, 362, 357, 360, 357, 360,
+- 357, 357, 357, 357, 426, 357, 187, 188,
+- 189, 357, 357, 357, 362, 357, 360, 357,
+- 360, 357, 425, 357, 357, 357, 357, 187,
+- 188, 189, 357, 357, 357, 362, 357, 360,
+- 357, 360, 78, 357, 357, 95, 361, 357,
+- 187, 188, 189, 357, 357, 357, 362, 357,
+- 360, 357, 113, 80, 80, 81, 427, 427,
+- 427, 427, 427, 152, 113, 427, 183, 184,
+- 359, 359, 81, 187, 188, 189, 357, 357,
+- 357, 191, 357, 357, 194, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 357, 357, 196, 357, 113, 80, 80, 81,
+- 427, 427, 427, 427, 427, 427, 113, 427,
+- 429, 430, 431, 432, 119, 433, 434, 435,
+- 428, 428, 151, 436, 428, 428, 437, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 438, 428, 439, 430,
+- 432, 432, 119, 433, 434, 435, 428, 428,
+- 428, 436, 428, 428, 437, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 438, 428, 430, 432, 432, 119,
+- 433, 434, 435, 428, 428, 428, 436, 428,
+- 428, 437, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 438,
+- 428, 440, 428, 428, 428, 132, 441, 428,
+- 433, 434, 435, 428, 428, 428, 442, 428,
+- 440, 428, 443, 444, 445, 446, 119, 433,
+- 434, 435, 428, 428, 149, 447, 428, 428,
+- 437, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 438, 428,
+- 448, 444, 449, 449, 119, 433, 434, 435,
+- 428, 428, 428, 447, 428, 428, 437, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 438, 428, 444, 449,
+- 449, 119, 433, 434, 435, 428, 428, 428,
+- 447, 428, 428, 437, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 438, 428, 450, 428, 428, 428, 132,
+- 451, 428, 433, 434, 435, 428, 428, 428,
+- 442, 428, 450, 428, 452, 453, 454, 455,
+- 119, 433, 434, 435, 428, 428, 147, 456,
+- 428, 428, 437, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 438, 428, 457, 453, 458, 458, 119, 433,
+- 434, 435, 428, 428, 428, 456, 428, 428,
+- 437, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 438, 428,
+- 453, 458, 458, 119, 433, 434, 435, 428,
+- 428, 428, 456, 428, 428, 437, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 438, 428, 459, 428, 428,
+- 428, 132, 460, 428, 433, 434, 435, 428,
+- 428, 428, 442, 428, 459, 428, 461, 462,
+- 463, 464, 119, 433, 434, 435, 428, 428,
+- 145, 465, 428, 428, 437, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 438, 428, 466, 462, 467, 467,
+- 119, 433, 434, 435, 428, 428, 428, 465,
+- 428, 428, 437, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 438, 428, 462, 467, 467, 119, 433, 434,
+- 435, 428, 428, 428, 465, 428, 428, 437,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 438, 428, 468,
+- 428, 428, 428, 132, 469, 428, 433, 434,
+- 435, 428, 428, 428, 442, 428, 468, 428,
+- 470, 471, 472, 473, 119, 433, 434, 435,
+- 428, 428, 143, 474, 428, 428, 437, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 438, 428, 475, 471,
+- 476, 476, 119, 433, 434, 435, 428, 428,
+- 428, 474, 428, 428, 437, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 438, 428, 471, 476, 476, 119,
+- 433, 434, 435, 428, 428, 428, 474, 428,
+- 428, 437, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 438,
+- 428, 132, 477, 428, 433, 434, 435, 428,
+- 428, 428, 442, 428, 433, 434, 435, 428,
+- 428, 428, 442, 428, 478, 428, 428, 479,
+- 434, 435, 428, 434, 435, 428, 480, 428,
+- 434, 481, 428, 434, 482, 428, 434, 428,
+- 478, 428, 428, 428, 434, 435, 428, 483,
+- 428, 484, 485, 428, 433, 434, 435, 428,
+- 428, 117, 428, 116, 428, 428, 428, 428,
+- 433, 434, 435, 428, 433, 434, 435, 428,
+- 483, 428, 428, 428, 428, 433, 434, 435,
+- 428, 483, 428, 484, 428, 428, 433, 434,
+- 435, 428, 428, 117, 428, 132, 428, 486,
+- 486, 119, 433, 434, 435, 428, 428, 428,
+- 442, 428, 487, 141, 488, 489, 122, 433,
+- 434, 435, 428, 428, 428, 442, 428, 141,
+- 488, 489, 122, 433, 434, 435, 428, 428,
+- 428, 442, 428, 488, 488, 122, 433, 434,
+- 435, 428, 428, 428, 442, 428, 490, 138,
+- 491, 492, 125, 433, 434, 435, 428, 428,
+- 428, 442, 428, 138, 491, 492, 125, 433,
+- 434, 435, 428, 428, 428, 442, 428, 491,
+- 491, 125, 433, 434, 435, 428, 428, 428,
+- 442, 428, 493, 135, 494, 495, 128, 433,
+- 434, 435, 428, 428, 428, 442, 428, 135,
+- 494, 495, 128, 433, 434, 435, 428, 428,
+- 428, 442, 428, 494, 494, 128, 433, 434,
+- 435, 428, 428, 428, 442, 428, 496, 132,
+- 428, 497, 428, 433, 434, 435, 428, 428,
+- 428, 442, 428, 132, 428, 497, 428, 433,
+- 434, 435, 428, 428, 428, 442, 428, 498,
+- 428, 433, 434, 435, 428, 428, 428, 442,
+- 428, 132, 428, 428, 428, 428, 433, 434,
+- 435, 428, 428, 428, 442, 428, 115, 116,
+- 428, 428, 132, 477, 428, 433, 434, 435,
+- 428, 428, 428, 442, 428, 115, 428, 471,
+- 476, 476, 119, 433, 434, 435, 428, 428,
+- 428, 474, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 438, 428, 471, 476, 476, 119,
+- 433, 434, 435, 428, 428, 428, 474, 428,
+- 470, 471, 476, 476, 119, 433, 434, 435,
+- 428, 428, 428, 474, 428, 428, 437, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 438, 428, 470, 471,
+- 472, 476, 119, 433, 434, 435, 428, 428,
+- 143, 474, 428, 428, 437, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 438, 428, 468, 428, 499, 428,
+- 486, 486, 119, 433, 434, 435, 428, 428,
+- 428, 442, 428, 468, 428, 468, 428, 428,
+- 428, 428, 428, 428, 433, 434, 435, 428,
+- 428, 428, 442, 428, 468, 428, 468, 428,
+- 428, 428, 428, 500, 428, 433, 434, 435,
+- 428, 428, 428, 442, 428, 468, 428, 468,
+- 428, 499, 428, 428, 428, 428, 433, 434,
+- 435, 428, 428, 428, 442, 428, 468, 428,
+- 468, 116, 428, 428, 132, 469, 428, 433,
+- 434, 435, 428, 428, 428, 442, 428, 468,
+- 428, 461, 462, 467, 467, 119, 433, 434,
+- 435, 428, 428, 428, 465, 428, 428, 437,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 438, 428, 461,
+- 462, 463, 467, 119, 433, 434, 435, 428,
+- 428, 145, 465, 428, 428, 437, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 438, 428, 459, 428, 501,
+- 428, 486, 486, 119, 433, 434, 435, 428,
+- 428, 428, 442, 428, 459, 428, 459, 428,
+- 428, 428, 428, 428, 428, 433, 434, 435,
+- 428, 428, 428, 442, 428, 459, 428, 459,
+- 428, 428, 428, 428, 502, 428, 433, 434,
+- 435, 428, 428, 428, 442, 428, 459, 428,
+- 459, 428, 501, 428, 428, 428, 428, 433,
+- 434, 435, 428, 428, 428, 442, 428, 459,
+- 428, 459, 116, 428, 428, 132, 460, 428,
+- 433, 434, 435, 428, 428, 428, 442, 428,
+- 459, 428, 452, 453, 458, 458, 119, 433,
+- 434, 435, 428, 428, 428, 456, 428, 428,
+- 437, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 438, 428,
+- 452, 453, 454, 458, 119, 433, 434, 435,
+- 428, 428, 147, 456, 428, 428, 437, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 438, 428, 450, 428,
+- 503, 428, 486, 486, 119, 433, 434, 435,
+- 428, 428, 428, 442, 428, 450, 428, 450,
+- 428, 428, 428, 428, 428, 428, 433, 434,
+- 435, 428, 428, 428, 442, 428, 450, 428,
+- 450, 428, 428, 428, 428, 504, 428, 433,
+- 434, 435, 428, 428, 428, 442, 428, 450,
+- 428, 450, 428, 503, 428, 428, 428, 428,
+- 433, 434, 435, 428, 428, 428, 442, 428,
+- 450, 428, 450, 116, 428, 428, 132, 451,
+- 428, 433, 434, 435, 428, 428, 428, 442,
+- 428, 450, 428, 443, 444, 449, 449, 119,
+- 433, 434, 435, 428, 428, 428, 447, 428,
+- 428, 437, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 438,
+- 428, 443, 444, 445, 449, 119, 433, 434,
+- 435, 428, 428, 149, 447, 428, 428, 437,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 438, 428, 440,
+- 428, 505, 428, 486, 486, 119, 433, 434,
+- 435, 428, 428, 428, 442, 428, 440, 428,
+- 440, 428, 428, 428, 428, 428, 428, 433,
+- 434, 435, 428, 428, 428, 442, 428, 440,
+- 428, 440, 428, 428, 428, 428, 506, 428,
+- 433, 434, 435, 428, 428, 428, 442, 428,
+- 440, 428, 440, 428, 505, 428, 428, 428,
+- 428, 433, 434, 435, 428, 428, 428, 442,
+- 428, 440, 428, 440, 116, 428, 428, 132,
+- 441, 428, 433, 434, 435, 428, 428, 428,
+- 442, 428, 440, 428, 429, 430, 432, 432,
+- 119, 433, 434, 435, 428, 428, 428, 436,
+- 428, 428, 437, 428, 428, 428, 428, 428,
+- 428, 428, 428, 428, 428, 428, 428, 428,
+- 438, 428, 181, 182, 183, 184, 507, 359,
+- 81, 187, 188, 189, 190, 190, 152, 191,
+- 357, 181, 194, 357, 357, 357, 357, 357,
+- 357, 357, 357, 357, 357, 357, 357, 357,
+- 196, 357, 198, 508, 200, 201, 5, 202,
+- 203, 204, 197, 197, 37, 205, 197, 197,
+- 206, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 207, 197,
+- 210, 182, 183, 184, 509, 510, 81, 511,
+- 512, 513, 197, 190, 152, 514, 197, 210,
+- 194, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 196, 197,
+- 113, 80, 80, 81, 202, 203, 204, 197,
+- 197, 152, 515, 197, 516, 2, 357, 357,
+- 357, 426, 357, 187, 188, 189, 357, 357,
+- 357, 362, 357, 516, 357, 517, 364, 518,
+- 519, 81, 511, 512, 513, 197, 197, 153,
+- 367, 197, 197, 194, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 196, 197, 520, 364, 369, 369, 81,
+- 511, 512, 513, 197, 197, 197, 367, 197,
+- 197, 194, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 196,
+- 197, 364, 369, 369, 81, 511, 512, 513,
+- 197, 197, 197, 367, 197, 197, 194, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 196, 197, 521, 197,
+- 197, 522, 512, 513, 197, 512, 513, 197,
+- 250, 197, 512, 523, 197, 512, 524, 197,
+- 512, 197, 521, 197, 197, 197, 512, 513,
+- 197, 517, 364, 369, 369, 81, 511, 512,
+- 513, 197, 197, 197, 367, 197, 197, 194,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 197, 197, 196, 197, 517,
+- 364, 518, 369, 81, 511, 512, 513, 197,
+- 197, 153, 367, 197, 197, 194, 197, 197,
+- 197, 197, 197, 197, 197, 197, 197, 197,
+- 197, 197, 197, 196, 197, 210, 197, 275,
+- 113, 525, 525, 155, 202, 203, 204, 197,
+- 197, 197, 515, 197, 210, 197, 526, 179,
+- 527, 528, 157, 511, 512, 513, 197, 197,
+- 197, 529, 197, 179, 527, 528, 157, 511,
+- 512, 513, 197, 197, 197, 529, 197, 527,
+- 527, 157, 511, 512, 513, 197, 197, 197,
+- 529, 197, 530, 176, 531, 532, 160, 511,
+- 512, 513, 197, 197, 197, 529, 197, 176,
+- 531, 532, 160, 511, 512, 513, 197, 197,
+- 197, 529, 197, 531, 531, 160, 511, 512,
+- 513, 197, 197, 197, 529, 197, 533, 173,
+- 534, 535, 163, 511, 512, 513, 197, 197,
+- 197, 529, 197, 173, 534, 535, 163, 511,
+- 512, 513, 197, 197, 197, 529, 197, 534,
+- 534, 163, 511, 512, 513, 197, 197, 197,
+- 529, 197, 536, 170, 197, 537, 197, 511,
+- 512, 513, 197, 197, 197, 529, 197, 170,
+- 197, 537, 197, 511, 512, 513, 197, 197,
+- 197, 529, 197, 511, 512, 513, 197, 197,
+- 197, 529, 197, 538, 197, 539, 540, 197,
+- 511, 512, 513, 197, 197, 167, 197, 166,
+- 197, 197, 197, 197, 511, 512, 513, 197,
+- 511, 512, 513, 197, 538, 197, 197, 197,
+- 197, 511, 512, 513, 197, 538, 197, 539,
+- 197, 197, 511, 512, 513, 197, 197, 167,
+- 197, 516, 166, 357, 357, 95, 361, 357,
+- 187, 188, 189, 357, 357, 357, 362, 357,
+- 516, 357, 542, 541, 541, 541, 541, 543,
+- 544, 545, 541, 543, 544, 545, 541, 546,
+- 541, 541, 547, 544, 545, 541, 544, 545,
+- 541, 548, 541, 544, 549, 541, 544, 550,
+- 541, 544, 541, 546, 541, 541, 541, 544,
+- 545, 541, 0
++ 1, 0, 2, 3, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 2, 0, 1, 0, 0, 0, 0,
++ 4, 0, 5, 5, 6, 1, 0, 7,
++ 7, 6, 0, 6, 0, 8, 8, 9,
++ 1, 0, 10, 10, 9, 0, 9, 0,
++ 11, 11, 12, 1, 0, 13, 13, 12,
++ 0, 12, 0, 14, 14, 15, 1, 0,
++ 16, 16, 15, 0, 15, 0, 17, 0,
++ 0, 0, 1, 0, 18, 0, 19, 0,
++ 20, 14, 14, 15, 1, 0, 21, 0,
++ 22, 0, 23, 11, 11, 12, 1, 0,
++ 24, 0, 25, 0, 26, 8, 8, 9,
++ 1, 0, 27, 0, 28, 0, 29, 5,
++ 5, 6, 1, 0, 0, 0, 0, 0,
++ 29, 0, 29, 5, 5, 6, 1, 0,
++ 0, 0, 0, 30, 29, 0, 31, 5,
++ 5, 6, 1, 0, 0, 0, 0, 0,
++ 31, 0, 31, 5, 5, 6, 1, 0,
++ 0, 0, 0, 32, 31, 0, 33, 5,
++ 5, 6, 1, 0, 0, 0, 0, 0,
++ 33, 0, 33, 5, 5, 6, 1, 0,
++ 0, 0, 0, 34, 33, 0, 35, 5,
++ 5, 6, 1, 0, 0, 0, 0, 0,
++ 35, 0, 35, 5, 5, 6, 1, 0,
++ 0, 0, 0, 36, 35, 0, 37, 5,
++ 5, 6, 1, 0, 0, 0, 0, 0,
++ 37, 0, 37, 5, 5, 6, 1, 0,
++ 0, 0, 0, 38, 37, 0, 40, 39,
++ 41, 42, 39, 39, 39, 39, 39, 39,
++ 39, 39, 39, 39, 39, 39, 39, 41,
++ 39, 40, 39, 39, 39, 39, 43, 39,
++ 44, 44, 45, 40, 39, 46, 46, 45,
++ 39, 45, 39, 47, 47, 48, 40, 39,
++ 49, 49, 48, 39, 48, 39, 50, 50,
++ 51, 40, 39, 52, 52, 51, 39, 51,
++ 39, 53, 53, 54, 40, 39, 55, 55,
++ 54, 39, 54, 39, 56, 39, 39, 39,
++ 40, 39, 57, 39, 58, 39, 59, 53,
++ 53, 54, 40, 39, 60, 39, 61, 39,
++ 62, 50, 50, 51, 40, 39, 63, 39,
++ 64, 39, 65, 47, 47, 48, 40, 39,
++ 66, 39, 67, 39, 68, 44, 44, 45,
++ 40, 39, 39, 39, 39, 39, 68, 39,
++ 68, 44, 44, 45, 40, 39, 39, 39,
++ 39, 69, 68, 39, 70, 44, 44, 45,
++ 40, 39, 39, 39, 39, 39, 70, 39,
++ 70, 44, 44, 45, 40, 39, 39, 39,
++ 39, 71, 70, 39, 72, 44, 44, 45,
++ 40, 39, 39, 39, 39, 39, 72, 39,
++ 72, 44, 44, 45, 40, 39, 39, 39,
++ 39, 73, 72, 39, 74, 44, 44, 45,
++ 40, 39, 39, 39, 39, 39, 74, 39,
++ 74, 44, 44, 45, 40, 39, 39, 39,
++ 39, 75, 74, 39, 76, 44, 44, 45,
++ 40, 39, 39, 39, 39, 39, 76, 39,
++ 76, 44, 44, 45, 40, 39, 39, 39,
++ 39, 77, 76, 39, 79, 78, 80, 81,
++ 78, 78, 78, 78, 78, 78, 78, 78,
++ 78, 78, 78, 78, 78, 80, 78, 79,
++ 78, 78, 78, 78, 82, 78, 83, 83,
++ 84, 79, 78, 86, 86, 84, 85, 84,
++ 85, 87, 87, 88, 79, 78, 89, 89,
++ 88, 78, 88, 78, 90, 90, 91, 79,
++ 78, 92, 92, 91, 78, 91, 78, 93,
++ 93, 94, 79, 78, 95, 95, 94, 78,
++ 94, 78, 96, 78, 78, 78, 79, 78,
++ 97, 78, 98, 78, 99, 93, 93, 94,
++ 79, 78, 100, 78, 101, 78, 102, 90,
++ 90, 91, 79, 78, 103, 78, 104, 78,
++ 105, 87, 87, 88, 79, 78, 106, 78,
++ 107, 78, 108, 83, 83, 84, 79, 78,
++ 78, 78, 78, 78, 108, 78, 108, 83,
++ 83, 84, 79, 78, 78, 78, 78, 109,
++ 108, 78, 110, 83, 83, 84, 79, 78,
++ 78, 78, 78, 78, 110, 78, 110, 83,
++ 83, 84, 79, 78, 78, 78, 78, 111,
++ 110, 78, 112, 83, 83, 84, 79, 78,
++ 78, 78, 78, 78, 112, 78, 112, 83,
++ 83, 84, 79, 78, 78, 78, 78, 113,
++ 112, 78, 114, 83, 83, 84, 79, 78,
++ 78, 78, 78, 78, 114, 78, 114, 83,
++ 83, 84, 79, 78, 78, 78, 78, 115,
++ 114, 78, 116, 83, 83, 84, 79, 78,
++ 78, 78, 78, 78, 116, 78, 118, 117,
++ 119, 120, 117, 117, 117, 117, 117, 117,
++ 117, 117, 117, 117, 117, 117, 117, 119,
++ 117, 118, 117, 117, 117, 117, 121, 117,
++ 122, 122, 123, 118, 117, 124, 124, 123,
++ 117, 123, 117, 125, 125, 126, 118, 117,
++ 127, 127, 126, 117, 126, 117, 128, 128,
++ 129, 118, 117, 130, 130, 129, 117, 129,
++ 117, 131, 131, 132, 118, 117, 133, 133,
++ 132, 117, 132, 117, 134, 117, 117, 117,
++ 118, 117, 135, 117, 136, 117, 137, 131,
++ 131, 132, 118, 117, 138, 117, 139, 117,
++ 140, 128, 128, 129, 118, 117, 141, 117,
++ 142, 117, 143, 125, 125, 126, 118, 117,
++ 144, 117, 145, 117, 146, 122, 122, 123,
++ 118, 117, 117, 117, 117, 117, 146, 117,
++ 146, 122, 122, 123, 118, 117, 117, 117,
++ 117, 147, 146, 117, 148, 122, 122, 123,
++ 118, 117, 117, 117, 117, 117, 148, 117,
++ 148, 122, 122, 123, 118, 117, 117, 117,
++ 117, 149, 148, 117, 150, 122, 122, 123,
++ 118, 117, 117, 117, 117, 117, 150, 117,
++ 150, 122, 122, 123, 118, 117, 117, 117,
++ 117, 151, 150, 117, 152, 122, 122, 123,
++ 118, 117, 117, 117, 117, 117, 152, 117,
++ 152, 122, 122, 123, 118, 117, 117, 117,
++ 117, 153, 152, 117, 154, 122, 122, 123,
++ 118, 117, 117, 117, 117, 117, 154, 117,
++ 154, 122, 122, 123, 118, 117, 117, 117,
++ 117, 155, 154, 117, 116, 83, 83, 84,
++ 79, 78, 78, 78, 78, 156, 116, 78,
++ 86, 86, 84, 1, 0, 114, 83, 83,
++ 84, 157, 0, 0, 0, 0, 0, 114,
++ 0, 114, 83, 83, 84, 157, 0, 0,
++ 0, 0, 158, 114, 0, 159, 159, 160,
++ 1, 0, 7, 7, 160, 0, 161, 161,
++ 162, 157, 0, 163, 163, 162, 0, 162,
++ 0, 164, 164, 165, 157, 0, 166, 166,
++ 165, 0, 165, 0, 167, 167, 168, 157,
++ 0, 169, 169, 168, 0, 168, 0, 157,
++ 0, 170, 171, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 170, 0, 157, 0, 0, 0, 0, 172,
++ 0, 173, 0, 0, 0, 157, 0, 174,
++ 0, 175, 0, 176, 167, 167, 168, 157,
++ 0, 177, 0, 178, 0, 179, 164, 164,
++ 165, 157, 0, 180, 0, 181, 0, 182,
++ 161, 161, 162, 157, 0, 183, 0, 184,
++ 0, 186, 185, 188, 189, 190, 191, 192,
++ 193, 84, 79, 194, 195, 196, 196, 156,
++ 197, 198, 199, 200, 201, 187, 187, 187,
++ 187, 187, 187, 187, 187, 187, 187, 187,
++ 187, 202, 187, 204, 205, 206, 207, 6,
++ 1, 208, 209, 203, 203, 38, 210, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 213, 205, 214, 214, 6, 1, 208,
++ 209, 203, 203, 203, 210, 203, 203, 211,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 212, 203, 205,
++ 214, 214, 6, 1, 208, 209, 203, 203,
++ 203, 210, 203, 203, 211, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 212, 203, 215, 203, 203, 203,
++ 19, 216, 203, 1, 208, 209, 203, 203,
++ 203, 217, 203, 215, 203, 218, 219, 220,
++ 221, 6, 1, 208, 209, 203, 203, 36,
++ 222, 203, 203, 211, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 212, 203, 223, 219, 224, 224, 6,
++ 1, 208, 209, 203, 203, 203, 222, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 219, 224, 224, 6, 1, 208, 209,
++ 203, 203, 203, 222, 203, 203, 211, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 212, 203, 225, 203,
++ 203, 203, 19, 226, 203, 1, 208, 209,
++ 203, 203, 203, 217, 203, 225, 203, 227,
++ 228, 229, 230, 6, 1, 208, 209, 203,
++ 203, 34, 231, 203, 203, 211, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 212, 203, 232, 228, 233,
++ 233, 6, 1, 208, 209, 203, 203, 203,
++ 231, 203, 203, 211, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 212, 203, 228, 233, 233, 6, 1,
++ 208, 209, 203, 203, 203, 231, 203, 203,
++ 211, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 212, 203,
++ 234, 203, 203, 203, 19, 235, 203, 1,
++ 208, 209, 203, 203, 203, 217, 203, 234,
++ 203, 236, 237, 238, 239, 6, 1, 208,
++ 209, 203, 203, 32, 240, 203, 203, 211,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 212, 203, 241,
++ 237, 242, 242, 6, 1, 208, 209, 203,
++ 203, 203, 240, 203, 203, 211, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 212, 203, 237, 242, 242,
++ 6, 1, 208, 209, 203, 203, 203, 240,
++ 203, 203, 211, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 212, 203, 243, 203, 203, 203, 19, 244,
++ 203, 1, 208, 209, 203, 203, 203, 217,
++ 203, 243, 203, 245, 246, 247, 248, 6,
++ 1, 208, 209, 203, 203, 30, 249, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 250, 246, 251, 251, 6, 1, 208,
++ 209, 203, 203, 203, 249, 203, 203, 211,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 212, 203, 246,
++ 251, 251, 6, 1, 208, 209, 203, 203,
++ 203, 249, 203, 203, 211, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 212, 203, 19, 252, 203, 1,
++ 208, 209, 203, 203, 203, 217, 203, 253,
++ 253, 203, 1, 208, 209, 203, 203, 203,
++ 217, 203, 254, 203, 203, 255, 208, 209,
++ 203, 208, 209, 203, 256, 203, 208, 257,
++ 203, 208, 258, 203, 208, 203, 254, 203,
++ 203, 203, 208, 209, 203, 259, 203, 260,
++ 261, 203, 1, 208, 209, 203, 203, 4,
++ 203, 3, 203, 253, 253, 203, 1, 208,
++ 209, 203, 253, 253, 203, 1, 208, 209,
++ 203, 259, 203, 253, 253, 203, 1, 208,
++ 209, 203, 259, 203, 260, 253, 203, 1,
++ 208, 209, 203, 203, 4, 203, 19, 203,
++ 262, 262, 6, 1, 208, 209, 203, 203,
++ 203, 217, 203, 263, 28, 264, 265, 9,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 28, 264, 265, 9, 1, 208, 209, 203,
++ 203, 203, 217, 203, 264, 264, 9, 1,
++ 208, 209, 203, 203, 203, 217, 203, 266,
++ 25, 267, 268, 12, 1, 208, 209, 203,
++ 203, 203, 217, 203, 25, 267, 268, 12,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 267, 267, 12, 1, 208, 209, 203, 203,
++ 203, 217, 203, 269, 22, 270, 271, 15,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 22, 270, 271, 15, 1, 208, 209, 203,
++ 203, 203, 217, 203, 270, 270, 15, 1,
++ 208, 209, 203, 203, 203, 217, 203, 272,
++ 19, 253, 273, 203, 1, 208, 209, 203,
++ 203, 203, 217, 203, 19, 253, 273, 203,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 253, 274, 203, 1, 208, 209, 203, 203,
++ 203, 217, 203, 19, 203, 253, 253, 203,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 2, 3, 203, 203, 19, 252, 203, 1,
++ 208, 209, 203, 203, 203, 217, 203, 2,
++ 203, 246, 251, 251, 6, 1, 208, 209,
++ 203, 203, 203, 249, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 212, 203, 246, 251,
++ 251, 6, 1, 208, 209, 203, 203, 203,
++ 249, 203, 245, 246, 251, 251, 6, 1,
++ 208, 209, 203, 203, 203, 249, 203, 203,
++ 211, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 212, 203,
++ 245, 246, 247, 251, 6, 1, 208, 209,
++ 203, 203, 30, 249, 203, 203, 211, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 212, 203, 243, 203,
++ 275, 203, 262, 262, 6, 1, 208, 209,
++ 203, 203, 203, 217, 203, 243, 203, 243,
++ 203, 203, 203, 253, 253, 203, 1, 208,
++ 209, 203, 203, 203, 217, 203, 243, 203,
++ 243, 203, 203, 203, 253, 276, 203, 1,
++ 208, 209, 203, 203, 203, 217, 203, 243,
++ 203, 243, 203, 275, 203, 253, 253, 203,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 243, 203, 243, 3, 203, 203, 19, 244,
++ 203, 1, 208, 209, 203, 203, 203, 217,
++ 203, 243, 203, 236, 237, 242, 242, 6,
++ 1, 208, 209, 203, 203, 203, 240, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 236, 237, 238, 242, 6, 1, 208,
++ 209, 203, 203, 32, 240, 203, 203, 211,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 212, 203, 234,
++ 203, 277, 203, 262, 262, 6, 1, 208,
++ 209, 203, 203, 203, 217, 203, 234, 203,
++ 234, 203, 203, 203, 253, 253, 203, 1,
++ 208, 209, 203, 203, 203, 217, 203, 234,
++ 203, 234, 203, 203, 203, 253, 278, 203,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 234, 203, 234, 203, 277, 203, 253, 253,
++ 203, 1, 208, 209, 203, 203, 203, 217,
++ 203, 234, 203, 234, 3, 203, 203, 19,
++ 235, 203, 1, 208, 209, 203, 203, 203,
++ 217, 203, 234, 203, 227, 228, 233, 233,
++ 6, 1, 208, 209, 203, 203, 203, 231,
++ 203, 203, 211, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 212, 203, 227, 228, 229, 233, 6, 1,
++ 208, 209, 203, 203, 34, 231, 203, 203,
++ 211, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 212, 203,
++ 225, 203, 279, 203, 262, 262, 6, 1,
++ 208, 209, 203, 203, 203, 217, 203, 225,
++ 203, 225, 203, 203, 203, 253, 253, 203,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 225, 203, 225, 203, 203, 203, 253, 280,
++ 203, 1, 208, 209, 203, 203, 203, 217,
++ 203, 225, 203, 225, 203, 279, 203, 253,
++ 253, 203, 1, 208, 209, 203, 203, 203,
++ 217, 203, 225, 203, 225, 3, 203, 203,
++ 19, 226, 203, 1, 208, 209, 203, 203,
++ 203, 217, 203, 225, 203, 218, 219, 224,
++ 224, 6, 1, 208, 209, 203, 203, 203,
++ 222, 203, 203, 211, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 212, 203, 218, 219, 220, 224, 6,
++ 1, 208, 209, 203, 203, 36, 222, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 215, 203, 281, 203, 262, 262, 6,
++ 1, 208, 209, 203, 203, 203, 217, 203,
++ 215, 203, 215, 203, 203, 203, 253, 253,
++ 203, 1, 208, 209, 203, 203, 203, 217,
++ 203, 215, 203, 215, 203, 203, 203, 253,
++ 282, 203, 1, 208, 209, 203, 203, 203,
++ 217, 203, 215, 203, 215, 203, 281, 203,
++ 253, 253, 203, 1, 208, 209, 203, 203,
++ 203, 217, 203, 215, 203, 215, 3, 203,
++ 203, 19, 216, 203, 1, 208, 209, 203,
++ 203, 203, 217, 203, 215, 203, 204, 205,
++ 214, 214, 6, 1, 208, 209, 203, 203,
++ 203, 210, 203, 203, 211, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 212, 203, 204, 205, 206, 214,
++ 6, 1, 208, 209, 203, 203, 38, 210,
++ 203, 203, 211, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 212, 203, 284, 285, 286, 287, 45, 40,
++ 288, 289, 283, 283, 77, 290, 283, 283,
++ 291, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 292, 283,
++ 293, 285, 294, 287, 45, 40, 288, 289,
++ 283, 283, 283, 290, 283, 283, 291, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 292, 283, 285, 294,
++ 287, 45, 40, 288, 289, 283, 283, 283,
++ 290, 283, 283, 291, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 292, 283, 295, 283, 283, 283, 58,
++ 296, 283, 40, 288, 289, 283, 283, 283,
++ 297, 283, 295, 283, 298, 299, 300, 301,
++ 45, 40, 288, 289, 283, 283, 75, 302,
++ 283, 283, 291, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 292, 283, 303, 299, 304, 304, 45, 40,
++ 288, 289, 283, 283, 283, 302, 283, 283,
++ 291, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 292, 283,
++ 299, 304, 304, 45, 40, 288, 289, 283,
++ 283, 283, 302, 283, 283, 291, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 292, 283, 305, 283, 283,
++ 283, 58, 306, 283, 40, 288, 289, 283,
++ 283, 283, 297, 283, 305, 283, 307, 308,
++ 309, 310, 45, 40, 288, 289, 283, 283,
++ 73, 311, 283, 283, 291, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 292, 283, 312, 308, 313, 313,
++ 45, 40, 288, 289, 283, 283, 283, 311,
++ 283, 283, 291, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 292, 283, 308, 313, 313, 45, 40, 288,
++ 289, 283, 283, 283, 311, 283, 283, 291,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 292, 283, 314,
++ 283, 283, 283, 58, 315, 283, 40, 288,
++ 289, 283, 283, 283, 297, 283, 314, 283,
++ 316, 317, 318, 319, 45, 40, 288, 289,
++ 283, 283, 71, 320, 283, 283, 291, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 292, 283, 321, 317,
++ 322, 322, 45, 40, 288, 289, 283, 283,
++ 283, 320, 283, 283, 291, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 292, 283, 317, 322, 322, 45,
++ 40, 288, 289, 283, 283, 283, 320, 283,
++ 283, 291, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 292,
++ 283, 323, 283, 283, 283, 58, 324, 283,
++ 40, 288, 289, 283, 283, 283, 297, 283,
++ 323, 283, 325, 326, 327, 328, 45, 40,
++ 288, 289, 283, 283, 69, 329, 283, 283,
++ 291, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 292, 283,
++ 330, 326, 331, 331, 45, 40, 288, 289,
++ 283, 283, 283, 329, 283, 283, 291, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 292, 283, 326, 331,
++ 331, 45, 40, 288, 289, 283, 283, 283,
++ 329, 283, 283, 291, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 292, 283, 58, 332, 283, 40, 288,
++ 289, 283, 283, 283, 297, 283, 333, 333,
++ 283, 40, 288, 289, 283, 283, 283, 297,
++ 283, 334, 283, 283, 335, 288, 289, 283,
++ 288, 289, 283, 336, 283, 288, 337, 283,
++ 288, 338, 283, 288, 283, 334, 283, 283,
++ 283, 288, 289, 283, 339, 283, 340, 341,
++ 283, 40, 288, 289, 283, 283, 43, 283,
++ 42, 283, 333, 333, 283, 40, 288, 289,
++ 283, 333, 333, 283, 40, 288, 289, 283,
++ 339, 283, 333, 333, 283, 40, 288, 289,
++ 283, 339, 283, 340, 333, 283, 40, 288,
++ 289, 283, 283, 43, 283, 58, 283, 342,
++ 342, 45, 40, 288, 289, 283, 283, 283,
++ 297, 283, 343, 67, 344, 345, 48, 40,
++ 288, 289, 283, 283, 283, 297, 283, 67,
++ 344, 345, 48, 40, 288, 289, 283, 283,
++ 283, 297, 283, 344, 344, 48, 40, 288,
++ 289, 283, 283, 283, 297, 283, 346, 64,
++ 347, 348, 51, 40, 288, 289, 283, 283,
++ 283, 297, 283, 64, 347, 348, 51, 40,
++ 288, 289, 283, 283, 283, 297, 283, 347,
++ 347, 51, 40, 288, 289, 283, 283, 283,
++ 297, 283, 349, 61, 350, 351, 54, 40,
++ 288, 289, 283, 283, 283, 297, 283, 61,
++ 350, 351, 54, 40, 288, 289, 283, 283,
++ 283, 297, 283, 350, 350, 54, 40, 288,
++ 289, 283, 283, 283, 297, 283, 352, 58,
++ 333, 353, 283, 40, 288, 289, 283, 283,
++ 283, 297, 283, 58, 333, 353, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 333,
++ 354, 283, 40, 288, 289, 283, 283, 283,
++ 297, 283, 58, 283, 333, 333, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 41,
++ 42, 283, 283, 58, 332, 283, 40, 288,
++ 289, 283, 283, 283, 297, 283, 41, 283,
++ 326, 331, 331, 45, 40, 288, 289, 283,
++ 283, 283, 329, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 292, 283, 326, 331, 331,
++ 45, 40, 288, 289, 283, 283, 283, 329,
++ 283, 325, 326, 331, 331, 45, 40, 288,
++ 289, 283, 283, 283, 329, 283, 283, 291,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 292, 283, 325,
++ 326, 327, 331, 45, 40, 288, 289, 283,
++ 283, 69, 329, 283, 283, 291, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 292, 283, 323, 283, 355,
++ 283, 342, 342, 45, 40, 288, 289, 283,
++ 283, 283, 297, 283, 323, 283, 323, 283,
++ 283, 283, 333, 333, 283, 40, 288, 289,
++ 283, 283, 283, 297, 283, 323, 283, 323,
++ 283, 283, 283, 333, 356, 283, 40, 288,
++ 289, 283, 283, 283, 297, 283, 323, 283,
++ 323, 283, 355, 283, 333, 333, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 323,
++ 283, 323, 42, 283, 283, 58, 324, 283,
++ 40, 288, 289, 283, 283, 283, 297, 283,
++ 323, 283, 316, 317, 322, 322, 45, 40,
++ 288, 289, 283, 283, 283, 320, 283, 283,
++ 291, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 292, 283,
++ 316, 317, 318, 322, 45, 40, 288, 289,
++ 283, 283, 71, 320, 283, 283, 291, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 292, 283, 314, 283,
++ 357, 283, 342, 342, 45, 40, 288, 289,
++ 283, 283, 283, 297, 283, 314, 283, 314,
++ 283, 283, 283, 333, 333, 283, 40, 288,
++ 289, 283, 283, 283, 297, 283, 314, 283,
++ 314, 283, 283, 283, 333, 358, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 314,
++ 283, 314, 283, 357, 283, 333, 333, 283,
++ 40, 288, 289, 283, 283, 283, 297, 283,
++ 314, 283, 314, 42, 283, 283, 58, 315,
++ 283, 40, 288, 289, 283, 283, 283, 297,
++ 283, 314, 283, 307, 308, 313, 313, 45,
++ 40, 288, 289, 283, 283, 283, 311, 283,
++ 283, 291, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 292,
++ 283, 307, 308, 309, 313, 45, 40, 288,
++ 289, 283, 283, 73, 311, 283, 283, 291,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 292, 283, 305,
++ 283, 359, 283, 342, 342, 45, 40, 288,
++ 289, 283, 283, 283, 297, 283, 305, 283,
++ 305, 283, 283, 283, 333, 333, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 305,
++ 283, 305, 283, 283, 283, 333, 360, 283,
++ 40, 288, 289, 283, 283, 283, 297, 283,
++ 305, 283, 305, 283, 359, 283, 333, 333,
++ 283, 40, 288, 289, 283, 283, 283, 297,
++ 283, 305, 283, 305, 42, 283, 283, 58,
++ 306, 283, 40, 288, 289, 283, 283, 283,
++ 297, 283, 305, 283, 298, 299, 304, 304,
++ 45, 40, 288, 289, 283, 283, 283, 302,
++ 283, 283, 291, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 292, 283, 298, 299, 300, 304, 45, 40,
++ 288, 289, 283, 283, 75, 302, 283, 283,
++ 291, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 283, 292, 283,
++ 295, 283, 361, 283, 342, 342, 45, 40,
++ 288, 289, 283, 283, 283, 297, 283, 295,
++ 283, 295, 283, 283, 283, 333, 333, 283,
++ 40, 288, 289, 283, 283, 283, 297, 283,
++ 295, 283, 295, 283, 283, 283, 333, 362,
++ 283, 40, 288, 289, 283, 283, 283, 297,
++ 283, 295, 283, 295, 283, 361, 283, 333,
++ 333, 283, 40, 288, 289, 283, 283, 283,
++ 297, 283, 295, 283, 76, 44, 44, 45,
++ 40, 283, 283, 283, 283, 283, 76, 283,
++ 295, 42, 283, 283, 58, 296, 283, 40,
++ 288, 289, 283, 283, 283, 297, 283, 295,
++ 283, 284, 285, 294, 287, 45, 40, 288,
++ 289, 283, 283, 283, 290, 283, 283, 291,
++ 283, 283, 283, 283, 283, 283, 283, 283,
++ 283, 283, 283, 283, 283, 292, 283, 364,
++ 191, 365, 365, 84, 79, 194, 195, 363,
++ 363, 363, 197, 363, 363, 200, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 202, 363, 191, 365, 365,
++ 84, 79, 194, 195, 363, 363, 363, 197,
++ 363, 363, 200, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 202, 363, 366, 363, 363, 363, 98, 367,
++ 363, 79, 194, 195, 363, 363, 363, 368,
++ 363, 366, 363, 369, 370, 371, 372, 84,
++ 79, 194, 195, 363, 363, 115, 373, 363,
++ 363, 200, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 202,
++ 363, 374, 370, 375, 375, 84, 79, 194,
++ 195, 363, 363, 363, 373, 363, 363, 200,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 202, 363, 370,
++ 375, 375, 84, 79, 194, 195, 363, 363,
++ 363, 373, 363, 363, 200, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 202, 363, 376, 363, 363, 363,
++ 98, 377, 363, 79, 194, 195, 363, 363,
++ 363, 368, 363, 376, 363, 378, 379, 380,
++ 381, 84, 79, 194, 195, 363, 363, 113,
++ 382, 363, 363, 200, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 202, 363, 383, 379, 384, 384, 84,
++ 79, 194, 195, 363, 363, 363, 382, 363,
++ 363, 200, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 202,
++ 363, 379, 384, 384, 84, 79, 194, 195,
++ 363, 363, 363, 382, 363, 363, 200, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 202, 363, 385, 363,
++ 363, 363, 98, 386, 363, 79, 194, 195,
++ 363, 363, 363, 368, 363, 385, 363, 387,
++ 388, 389, 390, 84, 79, 194, 195, 363,
++ 363, 111, 391, 363, 363, 200, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 202, 363, 392, 388, 393,
++ 393, 84, 79, 194, 195, 363, 363, 363,
++ 391, 363, 363, 200, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 202, 363, 388, 393, 393, 84, 79,
++ 194, 195, 363, 363, 363, 391, 363, 363,
++ 200, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 202, 363,
++ 394, 363, 363, 363, 98, 395, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 394,
++ 363, 396, 397, 398, 399, 84, 79, 194,
++ 195, 363, 363, 109, 400, 363, 363, 200,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 202, 363, 401,
++ 397, 402, 402, 84, 79, 194, 195, 363,
++ 363, 363, 400, 363, 363, 200, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 202, 363, 397, 402, 402,
++ 84, 79, 194, 195, 363, 363, 363, 400,
++ 363, 363, 200, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 202, 363, 98, 403, 363, 79, 194, 195,
++ 363, 363, 363, 368, 363, 404, 404, 363,
++ 79, 194, 195, 363, 363, 363, 368, 363,
++ 405, 363, 363, 406, 194, 195, 363, 194,
++ 195, 363, 407, 363, 194, 408, 363, 194,
++ 409, 363, 194, 363, 405, 363, 363, 363,
++ 194, 195, 363, 410, 363, 411, 412, 363,
++ 79, 194, 195, 363, 363, 82, 363, 81,
++ 363, 404, 404, 363, 79, 194, 195, 363,
++ 404, 404, 363, 79, 194, 195, 363, 410,
++ 363, 404, 404, 363, 79, 194, 195, 363,
++ 410, 363, 411, 404, 363, 79, 194, 195,
++ 363, 363, 82, 363, 98, 363, 413, 413,
++ 84, 79, 194, 195, 363, 363, 363, 368,
++ 363, 414, 107, 415, 416, 88, 79, 194,
++ 195, 363, 363, 363, 368, 363, 107, 415,
++ 416, 88, 79, 194, 195, 363, 363, 363,
++ 368, 363, 415, 415, 88, 79, 194, 195,
++ 363, 363, 363, 368, 363, 417, 104, 418,
++ 419, 91, 79, 194, 195, 363, 363, 363,
++ 368, 363, 104, 418, 419, 91, 79, 194,
++ 195, 363, 363, 363, 368, 363, 418, 418,
++ 91, 79, 194, 195, 363, 363, 363, 368,
++ 363, 420, 101, 421, 422, 94, 79, 194,
++ 195, 363, 363, 363, 368, 363, 101, 421,
++ 422, 94, 79, 194, 195, 363, 363, 363,
++ 368, 363, 421, 421, 94, 79, 194, 195,
++ 363, 363, 363, 368, 363, 423, 98, 404,
++ 424, 363, 79, 194, 195, 363, 363, 363,
++ 368, 363, 98, 404, 424, 363, 79, 194,
++ 195, 363, 363, 363, 368, 363, 404, 425,
++ 363, 79, 194, 195, 363, 363, 363, 368,
++ 363, 98, 363, 404, 404, 363, 79, 194,
++ 195, 363, 363, 363, 368, 363, 80, 81,
++ 363, 363, 98, 403, 363, 79, 194, 195,
++ 363, 363, 363, 368, 363, 80, 363, 397,
++ 402, 402, 84, 79, 194, 195, 363, 363,
++ 363, 400, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 202, 363, 397, 402, 402, 84,
++ 79, 194, 195, 363, 363, 363, 400, 363,
++ 396, 397, 402, 402, 84, 79, 194, 195,
++ 363, 363, 363, 400, 363, 363, 200, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 202, 363, 396, 397,
++ 398, 402, 84, 79, 194, 195, 363, 363,
++ 109, 400, 363, 363, 200, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 202, 363, 394, 363, 426, 363,
++ 413, 413, 84, 79, 194, 195, 363, 363,
++ 363, 368, 363, 394, 363, 394, 363, 363,
++ 363, 404, 404, 363, 79, 194, 195, 363,
++ 363, 363, 368, 363, 394, 363, 394, 363,
++ 363, 363, 404, 427, 363, 79, 194, 195,
++ 363, 363, 363, 368, 363, 394, 363, 394,
++ 363, 426, 363, 404, 404, 363, 79, 194,
++ 195, 363, 363, 363, 368, 363, 394, 363,
++ 394, 81, 363, 363, 98, 395, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 394,
++ 363, 387, 388, 393, 393, 84, 79, 194,
++ 195, 363, 363, 363, 391, 363, 363, 200,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 202, 363, 387,
++ 388, 389, 393, 84, 79, 194, 195, 363,
++ 363, 111, 391, 363, 363, 200, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 202, 363, 385, 363, 428,
++ 363, 413, 413, 84, 79, 194, 195, 363,
++ 363, 363, 368, 363, 385, 363, 385, 363,
++ 363, 363, 404, 404, 363, 79, 194, 195,
++ 363, 363, 363, 368, 363, 385, 363, 385,
++ 363, 363, 363, 404, 429, 363, 79, 194,
++ 195, 363, 363, 363, 368, 363, 385, 363,
++ 385, 363, 428, 363, 404, 404, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 385,
++ 363, 385, 81, 363, 363, 98, 386, 363,
++ 79, 194, 195, 363, 363, 363, 368, 363,
++ 385, 363, 378, 379, 384, 384, 84, 79,
++ 194, 195, 363, 363, 363, 382, 363, 363,
++ 200, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 202, 363,
++ 378, 379, 380, 384, 84, 79, 194, 195,
++ 363, 363, 113, 382, 363, 363, 200, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 202, 363, 376, 363,
++ 430, 363, 413, 413, 84, 79, 194, 195,
++ 363, 363, 363, 368, 363, 376, 363, 376,
++ 363, 363, 363, 404, 404, 363, 79, 194,
++ 195, 363, 363, 363, 368, 363, 376, 363,
++ 376, 363, 363, 363, 404, 431, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 376,
++ 363, 376, 363, 430, 363, 404, 404, 363,
++ 79, 194, 195, 363, 363, 363, 368, 363,
++ 376, 363, 376, 81, 363, 363, 98, 377,
++ 363, 79, 194, 195, 363, 363, 363, 368,
++ 363, 376, 363, 369, 370, 375, 375, 84,
++ 79, 194, 195, 363, 363, 363, 373, 363,
++ 363, 200, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 202,
++ 363, 369, 370, 371, 375, 84, 79, 194,
++ 195, 363, 363, 115, 373, 363, 363, 200,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 202, 363, 366,
++ 363, 432, 363, 413, 413, 84, 79, 194,
++ 195, 363, 363, 363, 368, 363, 366, 363,
++ 366, 363, 363, 363, 404, 404, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 366,
++ 363, 366, 363, 363, 363, 404, 433, 363,
++ 79, 194, 195, 363, 363, 363, 368, 363,
++ 366, 363, 366, 363, 432, 363, 404, 404,
++ 363, 79, 194, 195, 363, 363, 363, 368,
++ 363, 366, 363, 366, 81, 363, 363, 98,
++ 367, 363, 79, 194, 195, 363, 363, 363,
++ 368, 363, 366, 363, 116, 83, 83, 84,
++ 79, 434, 434, 434, 434, 156, 116, 434,
++ 190, 191, 365, 365, 84, 79, 194, 195,
++ 363, 363, 363, 197, 363, 363, 200, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 363, 363, 363, 202, 363, 116, 83,
++ 83, 84, 79, 434, 434, 434, 434, 434,
++ 116, 434, 436, 437, 438, 439, 123, 118,
++ 440, 441, 435, 435, 155, 442, 435, 435,
++ 443, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 444, 435,
++ 445, 437, 439, 439, 123, 118, 440, 441,
++ 435, 435, 435, 442, 435, 435, 443, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 444, 435, 437, 439,
++ 439, 123, 118, 440, 441, 435, 435, 435,
++ 442, 435, 435, 443, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 444, 435, 446, 435, 435, 435, 136,
++ 447, 435, 118, 440, 441, 435, 435, 435,
++ 448, 435, 446, 435, 449, 450, 451, 452,
++ 123, 118, 440, 441, 435, 435, 153, 453,
++ 435, 435, 443, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 444, 435, 454, 450, 455, 455, 123, 118,
++ 440, 441, 435, 435, 435, 453, 435, 435,
++ 443, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 444, 435,
++ 450, 455, 455, 123, 118, 440, 441, 435,
++ 435, 435, 453, 435, 435, 443, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 444, 435, 456, 435, 435,
++ 435, 136, 457, 435, 118, 440, 441, 435,
++ 435, 435, 448, 435, 456, 435, 458, 459,
++ 460, 461, 123, 118, 440, 441, 435, 435,
++ 151, 462, 435, 435, 443, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 444, 435, 463, 459, 464, 464,
++ 123, 118, 440, 441, 435, 435, 435, 462,
++ 435, 435, 443, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 444, 435, 459, 464, 464, 123, 118, 440,
++ 441, 435, 435, 435, 462, 435, 435, 443,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 444, 435, 465,
++ 435, 435, 435, 136, 466, 435, 118, 440,
++ 441, 435, 435, 435, 448, 435, 465, 435,
++ 467, 468, 469, 470, 123, 118, 440, 441,
++ 435, 435, 149, 471, 435, 435, 443, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 444, 435, 472, 468,
++ 473, 473, 123, 118, 440, 441, 435, 435,
++ 435, 471, 435, 435, 443, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 444, 435, 468, 473, 473, 123,
++ 118, 440, 441, 435, 435, 435, 471, 435,
++ 435, 443, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 444,
++ 435, 474, 435, 435, 435, 136, 475, 435,
++ 118, 440, 441, 435, 435, 435, 448, 435,
++ 474, 435, 476, 477, 478, 479, 123, 118,
++ 440, 441, 435, 435, 147, 480, 435, 435,
++ 443, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 444, 435,
++ 481, 477, 482, 482, 123, 118, 440, 441,
++ 435, 435, 435, 480, 435, 435, 443, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 444, 435, 477, 482,
++ 482, 123, 118, 440, 441, 435, 435, 435,
++ 480, 435, 435, 443, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 444, 435, 136, 483, 435, 118, 440,
++ 441, 435, 435, 435, 448, 435, 484, 484,
++ 435, 118, 440, 441, 435, 435, 435, 448,
++ 435, 485, 435, 435, 486, 440, 441, 435,
++ 440, 441, 435, 487, 435, 440, 488, 435,
++ 440, 489, 435, 440, 435, 485, 435, 435,
++ 435, 440, 441, 435, 490, 435, 491, 492,
++ 435, 118, 440, 441, 435, 435, 121, 435,
++ 120, 435, 484, 484, 435, 118, 440, 441,
++ 435, 484, 484, 435, 118, 440, 441, 435,
++ 490, 435, 484, 484, 435, 118, 440, 441,
++ 435, 490, 435, 491, 484, 435, 118, 440,
++ 441, 435, 435, 121, 435, 136, 435, 493,
++ 493, 123, 118, 440, 441, 435, 435, 435,
++ 448, 435, 494, 145, 495, 496, 126, 118,
++ 440, 441, 435, 435, 435, 448, 435, 145,
++ 495, 496, 126, 118, 440, 441, 435, 435,
++ 435, 448, 435, 495, 495, 126, 118, 440,
++ 441, 435, 435, 435, 448, 435, 497, 142,
++ 498, 499, 129, 118, 440, 441, 435, 435,
++ 435, 448, 435, 142, 498, 499, 129, 118,
++ 440, 441, 435, 435, 435, 448, 435, 498,
++ 498, 129, 118, 440, 441, 435, 435, 435,
++ 448, 435, 500, 139, 501, 502, 132, 118,
++ 440, 441, 435, 435, 435, 448, 435, 139,
++ 501, 502, 132, 118, 440, 441, 435, 435,
++ 435, 448, 435, 501, 501, 132, 118, 440,
++ 441, 435, 435, 435, 448, 435, 503, 136,
++ 484, 504, 435, 118, 440, 441, 435, 435,
++ 435, 448, 435, 136, 484, 504, 435, 118,
++ 440, 441, 435, 435, 435, 448, 435, 484,
++ 505, 435, 118, 440, 441, 435, 435, 435,
++ 448, 435, 136, 435, 484, 484, 435, 118,
++ 440, 441, 435, 435, 435, 448, 435, 119,
++ 120, 435, 435, 136, 483, 435, 118, 440,
++ 441, 435, 435, 435, 448, 435, 119, 435,
++ 477, 482, 482, 123, 118, 440, 441, 435,
++ 435, 435, 480, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 444, 435, 477, 482, 482,
++ 123, 118, 440, 441, 435, 435, 435, 480,
++ 435, 476, 477, 482, 482, 123, 118, 440,
++ 441, 435, 435, 435, 480, 435, 435, 443,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 444, 435, 476,
++ 477, 478, 482, 123, 118, 440, 441, 435,
++ 435, 147, 480, 435, 435, 443, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 444, 435, 474, 435, 506,
++ 435, 493, 493, 123, 118, 440, 441, 435,
++ 435, 435, 448, 435, 474, 435, 474, 435,
++ 435, 435, 484, 484, 435, 118, 440, 441,
++ 435, 435, 435, 448, 435, 474, 435, 474,
++ 435, 435, 435, 484, 507, 435, 118, 440,
++ 441, 435, 435, 435, 448, 435, 474, 435,
++ 474, 435, 506, 435, 484, 484, 435, 118,
++ 440, 441, 435, 435, 435, 448, 435, 474,
++ 435, 474, 120, 435, 435, 136, 475, 435,
++ 118, 440, 441, 435, 435, 435, 448, 435,
++ 474, 435, 467, 468, 473, 473, 123, 118,
++ 440, 441, 435, 435, 435, 471, 435, 435,
++ 443, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 444, 435,
++ 467, 468, 469, 473, 123, 118, 440, 441,
++ 435, 435, 149, 471, 435, 435, 443, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 444, 435, 465, 435,
++ 508, 435, 493, 493, 123, 118, 440, 441,
++ 435, 435, 435, 448, 435, 465, 435, 465,
++ 435, 435, 435, 484, 484, 435, 118, 440,
++ 441, 435, 435, 435, 448, 435, 465, 435,
++ 465, 435, 435, 435, 484, 509, 435, 118,
++ 440, 441, 435, 435, 435, 448, 435, 465,
++ 435, 465, 435, 508, 435, 484, 484, 435,
++ 118, 440, 441, 435, 435, 435, 448, 435,
++ 465, 435, 465, 120, 435, 435, 136, 466,
++ 435, 118, 440, 441, 435, 435, 435, 448,
++ 435, 465, 435, 458, 459, 464, 464, 123,
++ 118, 440, 441, 435, 435, 435, 462, 435,
++ 435, 443, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 444,
++ 435, 458, 459, 460, 464, 123, 118, 440,
++ 441, 435, 435, 151, 462, 435, 435, 443,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 444, 435, 456,
++ 435, 510, 435, 493, 493, 123, 118, 440,
++ 441, 435, 435, 435, 448, 435, 456, 435,
++ 456, 435, 435, 435, 484, 484, 435, 118,
++ 440, 441, 435, 435, 435, 448, 435, 456,
++ 435, 456, 435, 435, 435, 484, 511, 435,
++ 118, 440, 441, 435, 435, 435, 448, 435,
++ 456, 435, 456, 435, 510, 435, 484, 484,
++ 435, 118, 440, 441, 435, 435, 435, 448,
++ 435, 456, 435, 456, 120, 435, 435, 136,
++ 457, 435, 118, 440, 441, 435, 435, 435,
++ 448, 435, 456, 435, 449, 450, 455, 455,
++ 123, 118, 440, 441, 435, 435, 435, 453,
++ 435, 435, 443, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 444, 435, 449, 450, 451, 455, 123, 118,
++ 440, 441, 435, 435, 153, 453, 435, 435,
++ 443, 435, 435, 435, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 444, 435,
++ 446, 435, 512, 435, 493, 493, 123, 118,
++ 440, 441, 435, 435, 435, 448, 435, 446,
++ 435, 446, 435, 435, 435, 484, 484, 435,
++ 118, 440, 441, 435, 435, 435, 448, 435,
++ 446, 435, 446, 435, 435, 435, 484, 513,
++ 435, 118, 440, 441, 435, 435, 435, 448,
++ 435, 446, 435, 446, 435, 512, 435, 484,
++ 484, 435, 118, 440, 441, 435, 435, 435,
++ 448, 435, 446, 435, 446, 120, 435, 435,
++ 136, 447, 435, 118, 440, 441, 435, 435,
++ 435, 448, 435, 446, 435, 436, 437, 439,
++ 439, 123, 118, 440, 441, 435, 435, 435,
++ 442, 435, 435, 443, 435, 435, 435, 435,
++ 435, 435, 435, 435, 435, 435, 435, 435,
++ 435, 444, 435, 188, 189, 190, 191, 514,
++ 365, 84, 79, 194, 195, 196, 196, 156,
++ 197, 363, 188, 200, 363, 363, 363, 363,
++ 363, 363, 363, 363, 363, 363, 363, 363,
++ 363, 202, 363, 204, 515, 206, 207, 6,
++ 1, 208, 209, 203, 203, 38, 210, 203,
++ 203, 211, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 212,
++ 203, 215, 189, 190, 191, 516, 517, 84,
++ 157, 518, 519, 203, 196, 156, 520, 203,
++ 215, 200, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 202,
++ 203, 116, 521, 521, 84, 157, 208, 209,
++ 203, 203, 156, 522, 203, 523, 203, 203,
++ 524, 518, 519, 203, 518, 519, 203, 256,
++ 203, 518, 525, 203, 518, 526, 203, 518,
++ 203, 523, 203, 203, 203, 518, 519, 203,
++ 527, 3, 363, 363, 404, 433, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 527,
++ 363, 528, 370, 529, 530, 84, 157, 518,
++ 519, 203, 203, 158, 373, 203, 203, 200,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 202, 203, 531,
++ 370, 532, 532, 84, 157, 518, 519, 203,
++ 203, 203, 373, 203, 203, 200, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 202, 203, 370, 532, 532,
++ 84, 157, 518, 519, 203, 203, 203, 373,
++ 203, 203, 200, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 202, 203, 528, 370, 532, 532, 84, 157,
++ 518, 519, 203, 203, 203, 373, 203, 203,
++ 200, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 203, 203, 202, 203,
++ 528, 370, 529, 532, 84, 157, 518, 519,
++ 203, 203, 158, 373, 203, 203, 200, 203,
++ 203, 203, 203, 203, 203, 203, 203, 203,
++ 203, 203, 203, 203, 202, 203, 215, 203,
++ 281, 116, 533, 533, 160, 157, 208, 209,
++ 203, 203, 203, 522, 203, 215, 203, 534,
++ 184, 535, 536, 162, 157, 518, 519, 203,
++ 203, 203, 537, 203, 184, 535, 536, 162,
++ 157, 518, 519, 203, 203, 203, 537, 203,
++ 535, 535, 162, 157, 518, 519, 203, 203,
++ 203, 537, 203, 538, 181, 539, 540, 165,
++ 157, 518, 519, 203, 203, 203, 537, 203,
++ 181, 539, 540, 165, 157, 518, 519, 203,
++ 203, 203, 537, 203, 539, 539, 165, 157,
++ 518, 519, 203, 203, 203, 537, 203, 541,
++ 178, 542, 543, 168, 157, 518, 519, 203,
++ 203, 203, 537, 203, 178, 542, 543, 168,
++ 157, 518, 519, 203, 203, 203, 537, 203,
++ 542, 542, 168, 157, 518, 519, 203, 203,
++ 203, 537, 203, 544, 175, 545, 546, 203,
++ 157, 518, 519, 203, 203, 203, 537, 203,
++ 175, 545, 546, 203, 157, 518, 519, 203,
++ 203, 203, 537, 203, 545, 545, 203, 157,
++ 518, 519, 203, 203, 203, 537, 203, 547,
++ 203, 548, 549, 203, 157, 518, 519, 203,
++ 203, 172, 203, 171, 203, 545, 545, 203,
++ 157, 518, 519, 203, 545, 545, 203, 157,
++ 518, 519, 203, 547, 203, 545, 545, 203,
++ 157, 518, 519, 203, 547, 203, 548, 545,
++ 203, 157, 518, 519, 203, 203, 172, 203,
++ 527, 171, 363, 363, 98, 367, 363, 79,
++ 194, 195, 363, 363, 363, 368, 363, 527,
++ 363, 551, 550, 552, 552, 550, 186, 553,
++ 554, 550, 552, 552, 550, 186, 553, 554,
++ 550, 555, 550, 550, 556, 553, 554, 550,
++ 553, 554, 550, 557, 550, 553, 558, 550,
++ 553, 559, 550, 553, 550, 555, 550, 550,
++ 550, 553, 554, 550, 0
+ };
+
+ static const short _indic_syllable_machine_trans_targs[] = {
+- 170, 199, 201, 202, 3, 205, 4, 6,
+- 208, 7, 9, 211, 10, 12, 214, 13,
+- 15, 16, 191, 18, 19, 213, 21, 22,
+- 210, 24, 25, 207, 216, 221, 225, 228,
+- 232, 235, 239, 242, 246, 249, 170, 279,
+- 281, 282, 39, 285, 40, 42, 288, 43,
+- 45, 291, 46, 48, 294, 49, 51, 52,
+- 271, 54, 55, 293, 57, 58, 290, 60,
+- 61, 287, 296, 301, 305, 308, 312, 315,
+- 319, 322, 326, 330, 170, 358, 360, 361,
+- 75, 364, 170, 76, 78, 367, 79, 81,
+- 370, 82, 84, 373, 85, 87, 88, 350,
+- 90, 91, 372, 93, 94, 369, 96, 97,
+- 366, 375, 380, 384, 387, 391, 394, 398,
+- 401, 405, 170, 439, 441, 442, 110, 445,
+- 111, 113, 448, 114, 116, 451, 117, 119,
+- 454, 120, 122, 123, 431, 125, 126, 453,
+- 128, 129, 450, 131, 132, 447, 456, 461,
+- 465, 468, 472, 475, 479, 482, 486, 489,
+- 409, 505, 146, 508, 148, 511, 149, 151,
+- 514, 152, 154, 517, 155, 520, 522, 523,
+- 159, 160, 519, 162, 163, 516, 165, 166,
+- 513, 168, 169, 510, 170, 171, 251, 331,
+- 333, 408, 410, 351, 353, 354, 411, 407,
+- 490, 491, 378, 526, 379, 170, 172, 174,
+- 35, 250, 192, 194, 195, 248, 219, 220,
+- 173, 34, 175, 244, 0, 176, 178, 33,
+- 243, 241, 177, 32, 179, 237, 180, 182,
+- 31, 236, 234, 181, 30, 183, 230, 184,
+- 186, 29, 229, 227, 185, 28, 187, 223,
+- 188, 190, 27, 222, 218, 189, 26, 204,
+- 193, 198, 170, 196, 197, 200, 1, 203,
+- 2, 206, 5, 23, 209, 8, 20, 212,
+- 11, 17, 215, 14, 217, 224, 226, 231,
+- 233, 238, 240, 245, 247, 170, 252, 254,
+- 71, 328, 272, 274, 275, 329, 299, 300,
+- 253, 70, 255, 324, 36, 256, 258, 69,
+- 323, 321, 257, 68, 259, 317, 260, 262,
+- 67, 316, 314, 261, 66, 263, 310, 264,
+- 266, 65, 309, 307, 265, 64, 267, 303,
+- 268, 270, 63, 302, 298, 269, 62, 284,
+- 273, 278, 170, 276, 277, 280, 37, 283,
+- 38, 286, 41, 59, 289, 44, 56, 292,
+- 47, 53, 295, 50, 297, 304, 306, 311,
+- 313, 318, 320, 325, 327, 170, 332, 106,
+- 334, 403, 72, 335, 337, 105, 402, 400,
+- 336, 104, 338, 396, 339, 341, 103, 395,
+- 393, 340, 102, 342, 389, 343, 345, 101,
+- 388, 386, 344, 100, 346, 382, 347, 349,
+- 99, 381, 377, 348, 98, 363, 352, 357,
+- 170, 355, 356, 359, 73, 362, 74, 365,
+- 77, 95, 368, 80, 92, 371, 83, 89,
+- 374, 86, 376, 383, 385, 390, 392, 397,
+- 399, 404, 406, 170, 170, 412, 414, 142,
+- 141, 432, 434, 435, 488, 459, 460, 413,
+- 415, 484, 107, 416, 418, 140, 483, 481,
+- 417, 139, 419, 477, 420, 422, 138, 476,
+- 474, 421, 137, 423, 470, 424, 426, 136,
+- 469, 467, 425, 135, 427, 463, 428, 430,
+- 134, 462, 458, 429, 133, 444, 433, 438,
+- 170, 436, 437, 440, 108, 443, 109, 446,
+- 112, 130, 449, 115, 127, 452, 118, 124,
+- 455, 121, 457, 464, 466, 471, 473, 478,
+- 480, 485, 487, 143, 492, 493, 507, 498,
+- 500, 501, 525, 494, 495, 496, 144, 506,
+- 497, 499, 504, 502, 503, 145, 509, 147,
+- 167, 156, 512, 150, 164, 515, 153, 161,
+- 518, 158, 521, 157, 524, 170, 527, 528,
+- 530, 531, 529, 534, 170, 532, 533
++ 178, 200, 207, 209, 210, 4, 213, 5,
++ 7, 216, 8, 10, 219, 11, 13, 222,
++ 14, 16, 17, 199, 19, 20, 221, 22,
++ 23, 218, 25, 26, 215, 224, 229, 233,
++ 236, 240, 243, 247, 250, 254, 257, 178,
++ 280, 287, 289, 290, 41, 293, 42, 44,
++ 296, 45, 47, 299, 48, 50, 302, 51,
++ 53, 54, 279, 56, 57, 301, 59, 60,
++ 298, 62, 63, 295, 304, 309, 313, 316,
++ 320, 323, 327, 330, 334, 338, 178, 359,
++ 366, 368, 369, 78, 372, 178, 79, 81,
++ 375, 82, 84, 378, 85, 87, 381, 88,
++ 90, 91, 358, 93, 94, 380, 96, 97,
++ 377, 99, 100, 374, 383, 388, 392, 395,
++ 399, 402, 406, 409, 413, 178, 440, 447,
++ 449, 450, 114, 453, 115, 117, 456, 118,
++ 120, 459, 121, 123, 462, 124, 126, 127,
++ 439, 129, 130, 461, 132, 133, 458, 135,
++ 136, 455, 464, 469, 473, 476, 480, 483,
++ 487, 490, 494, 497, 417, 502, 513, 152,
++ 516, 154, 519, 155, 157, 522, 158, 160,
++ 525, 161, 528, 530, 531, 166, 167, 527,
++ 169, 170, 524, 172, 173, 521, 175, 176,
++ 518, 178, 536, 178, 179, 259, 339, 341,
++ 416, 418, 361, 362, 419, 415, 498, 499,
++ 386, 534, 387, 178, 180, 182, 36, 258,
++ 202, 203, 256, 227, 228, 181, 35, 183,
++ 252, 1, 184, 186, 34, 251, 249, 185,
++ 33, 187, 245, 188, 190, 32, 244, 242,
++ 189, 31, 191, 238, 192, 194, 30, 237,
++ 235, 193, 29, 195, 231, 196, 198, 28,
++ 230, 226, 197, 27, 212, 0, 201, 206,
++ 178, 204, 205, 208, 2, 211, 3, 214,
++ 6, 24, 217, 9, 21, 220, 12, 18,
++ 223, 15, 225, 232, 234, 239, 241, 246,
++ 248, 253, 255, 178, 260, 262, 73, 336,
++ 282, 283, 337, 307, 308, 261, 72, 263,
++ 332, 38, 264, 266, 71, 331, 329, 265,
++ 70, 267, 325, 268, 270, 69, 324, 322,
++ 269, 68, 271, 318, 272, 274, 67, 317,
++ 315, 273, 66, 275, 311, 276, 278, 65,
++ 310, 306, 277, 64, 292, 37, 281, 286,
++ 178, 284, 285, 288, 39, 291, 40, 294,
++ 43, 61, 297, 46, 58, 300, 49, 55,
++ 303, 52, 305, 312, 314, 319, 321, 326,
++ 328, 333, 335, 178, 340, 109, 342, 411,
++ 75, 343, 345, 108, 410, 408, 344, 107,
++ 346, 404, 347, 349, 106, 403, 401, 348,
++ 105, 350, 397, 351, 353, 104, 396, 394,
++ 352, 103, 354, 390, 355, 357, 102, 389,
++ 385, 356, 101, 371, 74, 360, 365, 178,
++ 363, 364, 367, 76, 370, 77, 373, 80,
++ 98, 376, 83, 95, 379, 86, 92, 382,
++ 89, 384, 391, 393, 398, 400, 405, 407,
++ 412, 414, 178, 178, 420, 422, 146, 145,
++ 442, 443, 496, 467, 468, 421, 423, 492,
++ 111, 424, 426, 144, 491, 489, 425, 143,
++ 427, 485, 428, 430, 142, 484, 482, 429,
++ 141, 431, 478, 432, 434, 140, 477, 475,
++ 433, 139, 435, 471, 436, 438, 138, 470,
++ 466, 437, 137, 452, 110, 441, 446, 178,
++ 444, 445, 448, 112, 451, 113, 454, 116,
++ 134, 457, 119, 131, 460, 122, 128, 463,
++ 125, 465, 472, 474, 479, 481, 486, 488,
++ 493, 495, 147, 500, 501, 515, 504, 505,
++ 533, 148, 509, 503, 508, 506, 507, 510,
++ 511, 150, 514, 512, 149, 151, 517, 153,
++ 174, 163, 520, 156, 171, 523, 159, 168,
++ 526, 162, 165, 529, 164, 532, 178, 535,
++ 177, 538, 539, 537, 542, 178, 540, 541
+ };
+
+ static const char _indic_syllable_machine_trans_actions[] = {
+- 1, 2, 0, 0, 0, 2, 0, 0,
++ 1, 0, 2, 2, 2, 0, 2, 0,
++ 0, 2, 0, 0, 2, 0, 0, 2,
++ 0, 0, 0, 2, 0, 0, 2, 0,
++ 0, 2, 0, 0, 2, 2, 2, 2,
++ 2, 2, 2, 2, 2, 2, 2, 3,
++ 0, 2, 2, 2, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 0,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 2, 0, 0, 2, 2, 2, 2, 2,
+- 2, 2, 2, 2, 2, 2, 3, 2,
+- 0, 0, 0, 2, 0, 0, 2, 0,
++ 2, 2, 2, 2, 2, 2, 4, 0,
++ 2, 2, 2, 0, 2, 5, 0, 0,
++ 2, 0, 0, 2, 0, 0, 2, 0,
++ 0, 0, 2, 0, 0, 2, 0, 0,
++ 2, 0, 0, 2, 2, 6, 2, 6,
++ 2, 6, 2, 6, 2, 7, 0, 2,
++ 2, 2, 0, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 2, 0, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 2, 4, 2, 0, 0,
+- 0, 2, 5, 0, 0, 2, 0, 0,
+- 2, 0, 0, 2, 0, 0, 0, 2,
+- 0, 0, 2, 0, 0, 2, 0, 0,
+- 2, 2, 6, 2, 6, 2, 6, 2,
+- 6, 2, 7, 2, 0, 0, 0, 2,
++ 2, 2, 2, 2, 6, 0, 8, 0,
++ 2, 0, 2, 0, 0, 2, 0, 0,
++ 2, 0, 2, 2, 2, 0, 0, 2,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+- 2, 0, 0, 0, 2, 0, 0, 2,
+- 0, 0, 2, 0, 0, 2, 2, 2,
+- 2, 2, 2, 2, 2, 2, 2, 2,
+- 6, 8, 0, 2, 0, 2, 0, 0,
+- 2, 0, 0, 2, 0, 2, 0, 0,
+- 0, 0, 2, 0, 0, 2, 0, 0,
+- 2, 0, 0, 2, 11, 2, 2, 6,
+- 2, 12, 12, 0, 0, 0, 2, 2,
+- 6, 2, 6, 0, 6, 13, 2, 2,
+- 0, 2, 0, 0, 0, 2, 2, 2,
+- 2, 0, 2, 2, 0, 2, 2, 0,
+- 2, 2, 2, 0, 2, 2, 2, 2,
+- 0, 2, 2, 2, 0, 2, 2, 2,
+- 2, 0, 2, 2, 2, 0, 2, 2,
+- 2, 2, 0, 2, 2, 2, 0, 2,
+- 0, 0, 14, 0, 0, 0, 0, 2,
+- 0, 2, 0, 0, 2, 0, 0, 2,
+- 0, 0, 2, 0, 2, 2, 2, 2,
+- 2, 2, 2, 2, 2, 15, 2, 2,
+- 0, 2, 0, 0, 0, 2, 2, 2,
+- 2, 0, 2, 2, 0, 2, 2, 0,
+- 2, 2, 2, 0, 2, 2, 2, 2,
+- 0, 2, 2, 2, 0, 2, 2, 2,
+- 2, 0, 2, 2, 2, 0, 2, 2,
+- 2, 2, 0, 2, 2, 2, 0, 2,
+- 0, 0, 16, 0, 0, 0, 0, 2,
+- 0, 2, 0, 0, 2, 0, 0, 2,
+- 0, 0, 2, 0, 2, 2, 2, 2,
+- 2, 2, 2, 2, 2, 17, 6, 0,
+- 6, 6, 0, 6, 2, 0, 6, 2,
+- 6, 0, 6, 6, 6, 2, 0, 6,
+- 2, 6, 0, 6, 6, 6, 2, 0,
+- 6, 2, 6, 0, 6, 6, 6, 2,
+- 0, 6, 2, 6, 0, 6, 0, 0,
+- 18, 0, 0, 0, 0, 2, 0, 2,
++ 2, 9, 0, 12, 2, 2, 6, 2,
++ 13, 13, 0, 0, 2, 2, 6, 2,
++ 6, 2, 6, 14, 2, 2, 0, 2,
++ 0, 0, 2, 2, 2, 2, 0, 2,
++ 2, 0, 2, 2, 0, 2, 2, 2,
++ 0, 2, 2, 2, 2, 0, 2, 2,
++ 2, 0, 2, 2, 2, 2, 0, 2,
++ 2, 2, 0, 2, 2, 2, 2, 0,
++ 2, 2, 2, 0, 2, 0, 0, 0,
++ 15, 0, 0, 2, 0, 2, 0, 2,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 2, 0, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 19, 20, 2, 2, 0,
+- 0, 0, 0, 0, 2, 2, 2, 2,
+- 2, 2, 0, 2, 2, 0, 2, 2,
++ 2, 2, 2, 16, 2, 2, 0, 2,
++ 0, 0, 2, 2, 2, 2, 0, 2,
++ 2, 0, 2, 2, 0, 2, 2, 2,
++ 0, 2, 2, 2, 2, 0, 2, 2,
+ 2, 0, 2, 2, 2, 2, 0, 2,
+ 2, 2, 0, 2, 2, 2, 2, 0,
+- 2, 2, 2, 0, 2, 2, 2, 2,
+- 0, 2, 2, 2, 0, 2, 0, 0,
+- 21, 0, 0, 0, 0, 2, 0, 2,
++ 2, 2, 2, 0, 2, 0, 0, 0,
++ 17, 0, 0, 2, 0, 2, 0, 2,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+ 2, 0, 2, 2, 2, 2, 2, 2,
+- 2, 2, 2, 0, 0, 8, 2, 0,
+- 0, 0, 2, 2, 8, 8, 0, 8,
+- 8, 0, 0, 0, 0, 0, 2, 0,
++ 2, 2, 2, 18, 6, 0, 6, 6,
++ 0, 6, 2, 0, 6, 2, 6, 0,
++ 6, 6, 6, 2, 0, 6, 2, 6,
++ 0, 6, 6, 6, 2, 0, 6, 2,
++ 6, 0, 6, 6, 6, 2, 0, 6,
++ 2, 6, 0, 6, 0, 0, 0, 19,
++ 0, 0, 2, 0, 2, 0, 2, 0,
++ 0, 2, 0, 0, 2, 0, 0, 2,
++ 0, 2, 2, 2, 2, 2, 2, 2,
++ 2, 2, 20, 21, 2, 2, 0, 0,
++ 0, 0, 2, 2, 2, 2, 2, 2,
++ 0, 2, 2, 0, 2, 2, 2, 0,
++ 2, 2, 2, 2, 0, 2, 2, 2,
++ 0, 2, 2, 2, 2, 0, 2, 2,
++ 2, 0, 2, 2, 2, 2, 0, 2,
++ 2, 2, 0, 2, 0, 0, 0, 22,
++ 0, 0, 2, 0, 2, 0, 2, 0,
++ 0, 2, 0, 0, 2, 0, 0, 2,
++ 0, 2, 2, 2, 2, 2, 2, 2,
++ 2, 2, 0, 0, 8, 2, 0, 0,
++ 2, 0, 2, 0, 0, 0, 0, 8,
++ 8, 0, 8, 8, 0, 0, 2, 0,
+ 0, 0, 2, 0, 0, 2, 0, 0,
+- 2, 0, 0, 0, 2, 22, 0, 0,
+- 0, 0, 0, 0, 23, 0, 0
++ 2, 0, 0, 2, 0, 2, 23, 2,
++ 0, 0, 0, 0, 0, 24, 0, 0
+ };
+
+ static const char _indic_syllable_machine_to_state_actions[] = {
+@@ -1331,7 +1354,8 @@
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 9, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -1401,7 +1425,8 @@
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+- 0, 0, 10, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 11, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -1454,83 +1479,84 @@
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+- 1, 1, 1, 1, 39, 39, 39, 39,
+- 39, 39, 39, 39, 39, 39, 39, 39,
+- 39, 39, 39, 39, 39, 39, 39, 39,
+- 39, 39, 39, 39, 39, 39, 39, 39,
+- 39, 39, 39, 39, 39, 39, 39, 39,
+- 77, 77, 77, 83, 83, 77, 77, 77,
+- 77, 77, 77, 77, 77, 77, 77, 77,
+- 77, 77, 77, 77, 77, 77, 77, 77,
+- 77, 77, 77, 77, 77, 77, 77, 77,
+- 83, 77, 77, 115, 115, 115, 115, 115,
+- 115, 115, 115, 115, 115, 115, 115, 115,
+- 115, 115, 115, 115, 115, 115, 115, 115,
+- 115, 115, 115, 115, 115, 115, 115, 115,
+- 115, 115, 115, 115, 115, 115, 115, 77,
++ 1, 1, 1, 1, 1, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 40, 40, 40, 40, 40, 40,
++ 40, 40, 79, 79, 79, 79, 86, 86,
++ 79, 79, 79, 79, 79, 79, 79, 79,
++ 79, 79, 79, 79, 79, 79, 79, 79,
++ 79, 79, 79, 79, 79, 79, 79, 79,
++ 79, 79, 79, 79, 79, 79, 118, 118,
++ 118, 118, 118, 118, 118, 118, 118, 118,
++ 118, 118, 118, 118, 118, 118, 118, 118,
++ 118, 118, 118, 118, 118, 118, 118, 118,
++ 118, 118, 118, 118, 118, 118, 118, 118,
++ 118, 118, 118, 79, 1, 1, 1, 1,
+ 1, 1, 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, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 278, 278, 278, 278, 278,
+- 278, 278, 278, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 358, 358, 358, 358, 358, 358, 358, 358,
+- 428, 358, 428, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 429, 429, 429, 429, 429, 429,
+- 429, 429, 358, 198, 198, 198, 358, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 198, 198, 198,
+- 198, 198, 198, 198, 198, 358, 542, 542,
+- 542, 542, 542, 542, 542, 542, 542
++ 1, 186, 0, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 284, 284, 284, 284, 284,
++ 284, 284, 284, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 364, 364, 364, 364, 364, 364, 364, 364,
++ 435, 364, 435, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 436, 436, 436, 436, 436, 436,
++ 436, 436, 364, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 364, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 204, 204, 204,
++ 204, 204, 204, 204, 204, 364, 551, 551,
++ 551, 551, 551, 551, 551, 551, 551
+ };
+
+-static const int indic_syllable_machine_start = 170;
+-static const int indic_syllable_machine_first_final = 170;
++static const int indic_syllable_machine_start = 178;
++static const int indic_syllable_machine_first_final = 178;
+ static const int indic_syllable_machine_error = -1;
+
+-static const int indic_syllable_machine_en_main = 170;
++static const int indic_syllable_machine_en_main = 178;
+
+
+-#line 36 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 36 "hb-ot-shape-complex-indic-machine.rl"
+
+
+
+-#line 97 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 97 "hb-ot-shape-complex-indic-machine.rl"
+
+
+ #define found_syllable(syllable_type) \
+@@ -1550,7 +1576,7 @@
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+-#line 1554 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 1580 "hb-ot-shape-complex-indic-machine.hh"
+ {
+ cs = indic_syllable_machine_start;
+ ts = 0;
+@@ -1558,7 +1584,7 @@
+ act = 0;
+ }
+
+-#line 118 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 118 "hb-ot-shape-complex-indic-machine.rl"
+
+
+ p = 0;
+@@ -1567,7 +1593,7 @@
+ unsigned int last = 0;
+ unsigned int syllable_serial = 1;
+
+-#line 1571 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 1597 "hb-ot-shape-complex-indic-machine.hh"
+ {
+ int _slen;
+ int _trans;
+@@ -1577,11 +1603,11 @@
+ goto _test_eof;
+ _resume:
+ switch ( _indic_syllable_machine_from_state_actions[cs] ) {
+- case 10:
++ case 11:
+ #line 1 "NONE"
+ {ts = p;}
+ break;
+-#line 1585 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 1611 "hb-ot-shape-complex-indic-machine.hh"
+ }
+
+ _keys = _indic_syllable_machine_trans_keys + (cs<<1);
+@@ -1603,68 +1629,72 @@
+ #line 1 "NONE"
+ {te = p+1;}
+ break;
+- case 14:
+-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 15:
++#line 88 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (consonant_syllable); }}
+ break;
+- case 16:
+-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 17:
++#line 89 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (vowel_syllable); }}
+ break;
+- case 21:
+-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 22:
++#line 90 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (standalone_cluster); }}
+ break;
+- case 23:
+-#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 24:
++#line 91 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (symbol_cluster); }}
+ break;
+- case 18:
+-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 19:
++#line 92 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (broken_cluster); }}
+ break;
+- case 11:
+-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 12:
++#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p+1;{ found_syllable (non_indic_cluster); }}
+ break;
+- case 13:
+-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 14:
++#line 88 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (consonant_syllable); }}
+ break;
+- case 15:
+-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 16:
++#line 89 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (vowel_syllable); }}
+ break;
+- case 20:
+-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 21:
++#line 90 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (standalone_cluster); }}
+ break;
+- case 22:
+-#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 23:
++#line 91 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (symbol_cluster); }}
+ break;
+- case 17:
+-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 18:
++#line 92 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (broken_cluster); }}
+ break;
+- case 19:
+-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
++ case 20:
++#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {te = p;p--;{ found_syllable (non_indic_cluster); }}
+ break;
+ case 1:
+-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 88 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+ break;
+ case 3:
+-#line 89 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 89 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
+ break;
+ case 7:
+-#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 90 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
+ break;
++ case 9:
++#line 91 "hb-ot-shape-complex-indic-machine.rl"
++ {{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
++ break;
+ case 4:
+-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 92 "hb-ot-shape-complex-indic-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+ break;
+ case 5:
+@@ -1685,31 +1715,31 @@
+ case 8:
+ #line 1 "NONE"
+ {te = p+1;}
+-#line 88 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 88 "hb-ot-shape-complex-indic-machine.rl"
+ {act = 1;}
+ break;
+ case 6:
+ #line 1 "NONE"
+ {te = p+1;}
+-#line 92 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 92 "hb-ot-shape-complex-indic-machine.rl"
+ {act = 5;}
+ break;
+- case 12:
++ case 13:
+ #line 1 "NONE"
+ {te = p+1;}
+-#line 93 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 93 "hb-ot-shape-complex-indic-machine.rl"
+ {act = 6;}
+ break;
+-#line 1704 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 1734 "hb-ot-shape-complex-indic-machine.hh"
+ }
+
+ _again:
+ switch ( _indic_syllable_machine_to_state_actions[cs] ) {
+- case 9:
++ case 10:
+ #line 1 "NONE"
+ {ts = 0;}
+ break;
+-#line 1713 "hb-ot-shape-complex-indic-machine.hh.tmp"
++#line 1743 "hb-ot-shape-complex-indic-machine.hh"
+ }
+
+ if ( ++p != pe )
+@@ -1725,7 +1755,7 @@
+
+ }
+
+-#line 127 "../../src/hb-ot-shape-complex-indic-machine.rl"
++#line 127 "hb-ot-shape-complex-indic-machine.rl"
+
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-private.hh gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh 2016-06-05 23:49:53.168841514 +0200
+@@ -109,27 +109,31 @@
+
+ INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
+ INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
+- INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */
+ INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_Repha, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
+- INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
+ INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
+ INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
+ INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
+- INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
+- INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
++ INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
+ INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
++ INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_M, /* Misc Khmer signs. */
+ INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
+ INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
+@@ -161,20 +165,24 @@
+ INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
+ };
+
+-/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
+- * because gcc fails to optimize the latter and fills the table in at runtime. */
+ #define INDIC_COMBINE_CATEGORIES(S,M) \
+- (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
+- ( \
+- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+- S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+- S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+- S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+- S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+- false)) + \
+- ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+- ((M << 8) | S))
++ ( \
++ ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
++ ( S | \
++ ( \
++ ( \
++ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
++ S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
++ S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
++ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
++ S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
++ S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
++ false \
++ ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
++ ) << 8 \
++ ) \
++ ) \
++ )
+
+ HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+ hb_indic_get_categories (hb_codepoint_t u);
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-table.cc gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-indic-table.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc 2016-06-05 23:49:54.888832464 +0200
+@@ -6,63 +6,67 @@
+ *
+ * on files with these headers:
+ *
+- * # IndicSyllabicCategory-7.0.0.txt
+- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+- * # IndicMatraCategory-7.0.0.txt
+- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+- * # Blocks-7.0.0.txt
+- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
++ * # IndicSyllabicCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # IndicPositionalCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # Blocks-8.0.0.txt
++ * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ */
+
+ #include "hb-ot-shape-complex-indic-private.hh"
+
+
+ #define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 13 chars; Avagraha */
+-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 59 chars; Bindu */
++#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 60 chars; Bindu */
+ #define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
+-#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 30 chars; Cantillation_Mark */
+-#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1744 chars; Consonant */
++#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 52 chars; Cantillation_Mark */
++#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1805 chars; Consonant */
+ #define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 7 chars; Consonant_Dead */
+-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 61 chars; Consonant_Final */
++#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 62 chars; Consonant_Final */
+ #define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
+-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 19 chars; Consonant_Medial */
+-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 11 chars; Consonant_Placeholder */
++#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
++#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 22 chars; Consonant_Medial */
++#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 13 chars; Consonant_Placeholder */
+ #define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 1 chars; Consonant_Preceding_Repha */
++#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 2 chars; Consonant_Prefixed */
+ #define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 61 chars; Consonant_Subjoined */
+ #define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
++#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 4 chars; Consonant_With_Stacker */
+ #define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 2 chars; Gemination_Mark */
+ #define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 7 chars; Invisible_Stacker */
+ #define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
+ #define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
+ #define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
+-#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 18 chars; Nukta */
+-#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 408 chars; Number */
++#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 23 chars; Nukta */
++#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 420 chars; Number */
+ #define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
+ #define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
+-#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 15 chars; Pure_Killer */
+-#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 3 chars; Register_Shifter */
++#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 16 chars; Pure_Killer */
++#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
++#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 20 chars; Syllable_Modifier */
+ #define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
+-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 62 chars; Tone_Mark */
++#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */
+ #define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 22 chars; Virama */
+ #define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 29 chars; Visarga */
+ #define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
+-#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 553 chars; Vowel_Dependent */
+-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 395 chars; Vowel_Independent */
++#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 572 chars; Vowel_Dependent */
++#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 404 chars; Vowel_Independent */
+
+-#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 142 chars; Bottom */
++#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 256 chars; Bottom */
+ #define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */
+-#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 57 chars; Left */
++#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 55 chars; Left */
+ #define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 21 chars; Left_And_Right */
+ #define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
+-#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */
+-#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 163 chars; Right */
+-#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 169 chars; Top */
++#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */
++#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 249 chars; Right */
++#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 324 chars; Top */
+ #define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
+ #define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
+ #define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */
+ #define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
+ #define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
+-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 15 chars; Visual_Order_Left */
++#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */
+
+ #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
+
+@@ -79,29 +83,33 @@
+ /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x00d0u 24
++#define indic_offset_0x00b0u 24
+
+
+ /* Latin-1 Supplement */
+
++ /* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
+
+-#define indic_offset_0x0900u 32
++#define indic_offset_0x0900u 64
+
+
+ /* Devanagari */
+
+- /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
+ /* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
+- /* 0950 */ _(x,x), _(TM,x), _(TM,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
++ /* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B),
+ /* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+@@ -110,14 +118,14 @@
+
+ /* Bengali */
+
+- /* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0980 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
+- /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
+ /* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
+ /* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+@@ -129,33 +137,33 @@
+
+ /* Gurmukhi */
+
+- /* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
+ /* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
+- /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(x,x), _(M,R), _(M,L),
++ /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L),
+ /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
+ /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
+ /* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
+ /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 0A70 */ _(Bi,x), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
++ /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x),
+ /* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Gujarati */
+
+- /* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
+ /* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
+ /* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
+ /* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -163,18 +171,18 @@
+ /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0AF8 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Oriya */
+
+- /* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
++ /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
+ /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
+ /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
+ /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR),
+@@ -186,7 +194,7 @@
+
+ /* Tamil */
+
+- /* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
+ /* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
+@@ -194,7 +202,7 @@
+ /* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
+ /* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
+- /* 0BC0 */ _(M,T), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
++ /* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
+ /* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
+ /* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -205,7 +213,7 @@
+
+ /* Telugu */
+
+- /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -216,7 +224,7 @@
+ /* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
+ /* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
+ /* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
+- /* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -224,26 +232,26 @@
+
+ /* Kannada */
+
+- /* 0C80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0C80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
++ /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
+ /* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
+ /* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
+ /* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
+ /* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
+ /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Malayalam */
+
+- /* 0D00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0D00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -254,7 +262,7 @@
+ /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
+ /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,x), _(x,x),
+ /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+- /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
+ /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -262,7 +270,7 @@
+
+ /* Sinhala */
+
+- /* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0D80 */ _(x,x), _(x,x), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
+ /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -278,7 +286,7 @@
+ /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1000u 1304
++#define indic_offset_0x1000u 1336
+
+
+ /* Myanmar */
+@@ -289,22 +297,22 @@
+ /* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
+- /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x),
+- /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
++ /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B),
++ /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B), _(C,x),
+ /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x),
+ /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
+- /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x),
+- /* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R),
+- /* 1068 */ _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
++ /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,B), _(CM,B),
++ /* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R),
++ /* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x),
+ /* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
+ /* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x),
+- /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x),
++ /* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R),
++ /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R),
+ /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
++ /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x),
+
+-#define indic_offset_0x1700u 1464
++#define indic_offset_0x1700u 1496
+
+
+ /* Tagalog */
+@@ -345,14 +353,14 @@
+ /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
+ /* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
+- /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
+- /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T), _(M,T), _(M,T), _(M,T),
+- /* 17D0 */ _(M,T), _(PK,T), _(IS,x), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x),
++ /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
++ /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
++ /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,T), _(x,x), _(x,x),
+ /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1900u 1704
++#define indic_offset_0x1900u 1736
+
+
+ /* Limbu */
+@@ -362,9 +370,9 @@
+ /* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
+ /* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T),
+- /* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1928 */ _(M,T), _(CS,R), _(CS,R), _(CS,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1930 */ _(CF,R), _(CF,R), _(Bi,B), _(CF,R), _(CF,R), _(CF,R), _(CF,R), _(CF,R),
++ /* 1938 */ _(CF,R), _(CF,B), _(M,T), _(SM,B), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+
+@@ -385,10 +393,10 @@
+ /* 1998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 19A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 19A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,L), _(M,L), _(M,L),
+- /* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
++ /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),_(M,VOL),_(M,VOL),_(M,VOL),
++ /* 19B8 */ _(M,R), _(M,R),_(M,VOL), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
+ /* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 19C8 */ _(TM,R), _(TM,R), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 19D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -411,47 +419,47 @@
+ /* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x),
+- /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,x), _(CF,x),
+- /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x),
++ /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,B), _(CF,R),
++ /* 1A58 */ _(CF,T), _(CF,T), _(CF,T), _(CF,B), _(CF,B), _(CF,B), _(CF,B), _(x,x),
+ /* 1A60 */ _(IS,x), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
+ /* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L),
+- /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x),
+- /* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,T), _(TM,T), _(TM,T),
++ /* 1A78 */ _(TM,T), _(TM,T), _(SM,T), _(SM,T), _(SM,T), _(x,x), _(x,x), _(SM,B),
+ /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A88 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A98 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1b00u 2120
++#define indic_offset_0x1b00u 2152
+
+
+ /* Balinese */
+
+- /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 1B00 */ _(Bi,T), _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,T), _(M,T),
++ /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,T), _(M,R), _(M,T), _(M,T),
+ /* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L),
+ /* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x),
+ /* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1B58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,T), _(x,B), _(x,T), _(x,T), _(x,T),
++ /* 1B70 */ _(x,T), _(x,T), _(x,T), _(x,T), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sundanese */
+
+- /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 1B80 */ _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R),
+- /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
++ /* 1BA0 */ _(C,x), _(CS,R), _(CS,B), _(CS,B), _(M,T), _(M,B), _(M,L), _(M,R),
++ /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,B), _(CS,B), _(C,x), _(C,x),
+ /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1BB8 */ _(Nd,x), _(Nd,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
+
+@@ -461,9 +469,9 @@
+ /* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,R),
++ /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,T), _(M,R),
+ /* 1BE8 */ _(M,T), _(M,T), _(M,R), _(M,R), _(M,R), _(M,T), _(M,R), _(M,T),
+- /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1BF0 */ _(CF,T), _(CF,T), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Lepcha */
+@@ -472,39 +480,49 @@
+ /* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1C10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L),
+- /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x),
+- /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L), _(x,x), _(N,x),
++ /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,R), _(CS,R), _(M,R), _(M,L),
++ /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,T), _(CF,T), _(CF,T),
++ /* 1C30 */ _(CF,T), _(CF,T), _(CF,T), _(CF,T), _(Bi,L), _(Bi,L), _(SM,T), _(N,B),
+ /* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1C48 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
+
+-#define indic_offset_0x1cd0u 2456
++#define indic_offset_0x1cd0u 2488
+
+
+ /* Vedic Extensions */
+
+- /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x), _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+- /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+- /* 1CE0 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(TM,x), _(x,x), _(x,x), _(x,x),
++ /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
++ /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
++ /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O),
++ /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x),
++ /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(Ca,T), _(x,x), _(x,x), _(x,x),
++ /* 1CF8 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x2008u 2496
++#define indic_offset_0x2008u 2536
+
+
+ /* General Punctuation */
+
+ /* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
+- /* 2010 */ _(x,x), _(x,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
++ /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0xa800u 2512
++#define indic_offset_0x2070u 2552
++
++
++ /* Superscripts and Subscripts */
++
++ /* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x),
++ /* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x),
++
++#define indic_offset_0xa800u 2576
+
+
+ /* Syloti Nagri */
+
+ /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T), _(C,x),
+- /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,T), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R),
+@@ -525,13 +543,13 @@
+
+ /* Saurashtra */
+
+- /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* A880 */ _(Bi,R), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A890 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A898 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A8A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A8A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(M,R), _(M,R), _(M,R),
++ /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,R), _(M,R), _(M,R), _(M,R),
+ /* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
+ /* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x),
+ /* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -540,9 +558,9 @@
+
+ /* Devanagari Extended */
+
+- /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+- /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+- /* A8F0 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
++ /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
++ /* A8F0 */ _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Kayah Li */
+@@ -552,15 +570,15 @@
+ /* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
+- /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x),
++ /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,B), _(TM,B), _(TM,B), _(x,x), _(x,x),
+
+ /* Rejang */
+
+ /* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B),
+- /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x),
+- /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,T),
++ /* A950 */ _(CF,T), _(CF,T), _(CF,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -569,14 +587,14 @@
+
+ /* Javanese */
+
+- /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* A980 */ _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,R), _(M,T), _(M,T),
+- /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x),
++ /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,T), _(M,R), _(M,R), _(M,T), _(M,T),
++ /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,R), _(CM,R), _(CM,R),
+ /* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+@@ -584,7 +602,7 @@
+
+ /* Myanmar Extended-B */
+
+- /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(C,x),
++ /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x),
+ /* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
+@@ -597,10 +615,10 @@
+ /* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L),
+- /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x), _(x,x),
++ /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,R), _(CM,L), _(CM,B), _(CM,B), _(x,x),
+ /* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x),
++ /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
++ /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,R), _(x,x), _(x,x),
+ /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* AA58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+@@ -609,7 +627,7 @@
+ /* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
++ /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
+
+ /* Tai Viet */
+
+@@ -620,8 +638,8 @@
+ /* AAA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAB0 */ _(M,T), _(M,R), _(M,T), _(M,T), _(M,B),_(M,VOL),_(M,VOL), _(M,T),
+- /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,x),
+- /* AAC0 */ _(TL,x), _(TM,x), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,T),
++ /* AAC0 */ _(TL,x), _(TM,T), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -630,9 +648,9 @@
+
+ /* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R),
+- /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(IS,x), _(x,x),
++ /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,R), _(IS,x), _(x,x),
+
+-#define indic_offset_0xabc0u 3272
++#define indic_offset_0xabc0u 3336
+
+
+ /* Meetei Mayek */
+@@ -642,31 +660,31 @@
+ /* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+ /* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R),
+- /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(PK,B), _(x,x), _(x,x),
++ /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,R), _(PK,B), _(x,x), _(x,x),
+ /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* ABF8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x10a00u 3336
++#define indic_offset_0x10a00u 3400
+
+
+ /* Kharoshthi */
+
+ /* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x),
+- /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x),
++ /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(M,B), _(Bi,B), _(Vs,T),
+ /* 10A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 10A18 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
++ /* 10A38 */ _(N,T), _(N,B), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
+ /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+
+-#define indic_offset_0x11000u 3408
++#define indic_offset_0x11000u 3472
+
+
+ /* Brahmi */
+
+- /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11000 */ _(Bi,R), _(Bi,T), _(Vs,R),_(CWS,x),_(CWS,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11010 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -685,21 +703,21 @@
+
+ /* Kaithi */
+
+- /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11080 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 11090 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11098 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R),
+- /* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 110B8 */ _(M,R), _(V,B), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11100u 3600
++#define indic_offset_0x11100u 3664
+
+
+ /* Chakma */
+
+- /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
++ /* 11100 */ _(Bi,T), _(Bi,T), _(Vs,T), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11110 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -716,12 +734,12 @@
+ /* 11158 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11160 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11168 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11178 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sharada */
+
+- /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11180 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11190 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11198 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -729,8 +747,8 @@
+ /* 111A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 111B0 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,L), _(M,R), _(M,B), _(M,B),
+ /* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR),
+- /* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 111C0 */ _(V,R), _(A,x),_(CPrf,x),_(CPrf,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 111C8 */ _(x,x), _(x,x), _(N,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x),
+ /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+@@ -749,11 +767,20 @@
+ /* 11218 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11220 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11228 */ _(C,x), _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,R), _(M,B),
+- /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,x), _(V,R), _(N,x), _(GM,T),
++ /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,T), _(V,R), _(N,T), _(GM,T),
+
+-#define indic_offset_0x112b0u 3912
++#define indic_offset_0x11280u 3976
+
+
++ /* Multani */
++
++ /* 11280 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(x,x),
++ /* 11288 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x),
++ /* 11290 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11298 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x),
++ /* 112A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 112A8 */ _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++
+ /* Khudawadi */
+
+ /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+@@ -761,15 +788,15 @@
+ /* 112C0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112C8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112D0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,x),
++ /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,T),
+ /* 112E0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
+- /* 112E8 */ _(M,T), _(N,x), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 112E8 */ _(M,T), _(N,B), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 112F8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Grantha */
+
+- /* 11300 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11300 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 11310 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 11318 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+@@ -781,11 +808,11 @@
+ /* 11348 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,R), _(x,x), _(x,x),
+ /* 11350 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 11358 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,x), _(Ca,x),
+- /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
+- /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
++ /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,T), _(Ca,T),
++ /* 11368 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x),
++ /* 11370 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11480u 4112
++#define indic_offset_0x11480u 4224
+
+
+ /* Tirhuta */
+@@ -797,13 +824,13 @@
+ /* 114A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+- /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,x),
+- /* 114C0 */ _(Bi,x), _(Vs,x), _(V,B), _(N,x), _(A,x), _(x,x), _(x,x), _(x,x),
++ /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,T),
++ /* 114C0 */ _(Bi,T), _(Vs,R), _(V,B), _(N,B), _(A,x), _(x,x), _(x,x), _(x,x),
+ /* 114C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 114D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11580u 4208
++#define indic_offset_0x11580u 4320
+
+
+ /* Siddham */
+@@ -815,11 +842,15 @@
+ /* 115A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 115A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,R),
+ /* 115B0 */ _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x),
+- /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x), _(V,B),
+- /* 115C0 */ _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+-
+-#define indic_offset_0x11600u 4280
+-
++ /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,T), _(Bi,T), _(Vs,R), _(V,B),
++ /* 115C0 */ _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115D8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x),
++ /* 115E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Modi */
+
+@@ -830,8 +861,8 @@
+ /* 11620 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11628 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11630 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+- /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,x), _(Vs,x), _(V,B),
+- /* 11640 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,T), _(Vs,R), _(V,B),
++ /* 11640 */ _(M,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11648 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 11658 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -847,13 +878,30 @@
+ /* 11690 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11698 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 116A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R),
+- /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x),
++ /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,T), _(Vs,R), _(M,T), _(M,L), _(M,R),
++ /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,R), _(N,B),
+ /* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 116C8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++
++ /* Ahom */
++
++ /* 11700 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11710 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11718 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(CM,B), _(CM,x), _(CM,T),
++ /* 11720 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T),
++ /* 11728 */ _(M,B), _(M,T), _(M,T), _(PK,T), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11730 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
++ /* 11738 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-}; /* Table items: 4488; occupancy: 73% */
++}; /* Table items: 4768; occupancy: 72% */
+
+ INDIC_TABLE_ELEMENT_TYPE
+ hb_indic_get_categories (hb_codepoint_t u)
+@@ -861,41 +909,41 @@
+ switch (u >> 12)
+ {
+ case 0x0u:
+- if (hb_in_range (u, 0x0028u, 0x0040u)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+- if (hb_in_range (u, 0x00D0u, 0x00D8u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
+- if (hb_in_range (u, 0x0900u, 0x0DF8u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
++ if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
++ if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
++ if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+ if (unlikely (u == 0x00A0u)) return _(CP,x);
+ break;
+
+ case 0x1u:
+- if (hb_in_range (u, 0x1000u, 0x10A0u)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+- if (hb_in_range (u, 0x1700u, 0x17F0u)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
+- if (hb_in_range (u, 0x1900u, 0x1AA0u)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
+- if (hb_in_range (u, 0x1B00u, 0x1C50u)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
+- if (hb_in_range (u, 0x1CD0u, 0x1CF8u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
++ if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
++ if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
++ if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
++ if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
++ if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+ break;
+
+ case 0x2u:
+- if (hb_in_range (u, 0x2008u, 0x2018u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
++ if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
++ if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+ if (unlikely (u == 0x25CCu)) return _(CP,x);
+ break;
+
+ case 0xAu:
+- if (hb_in_range (u, 0xA800u, 0xAAF8u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
+- if (hb_in_range (u, 0xABC0u, 0xAC00u)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
++ if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
++ if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
+ break;
+
+ case 0x10u:
+- if (hb_in_range (u, 0x10A00u, 0x10A48u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
++ if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
+ break;
+
+ case 0x11u:
+- if (hb_in_range (u, 0x11000u, 0x110C0u)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
+- if (hb_in_range (u, 0x11100u, 0x11238u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
+- if (hb_in_range (u, 0x112B0u, 0x11378u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
+- if (hb_in_range (u, 0x11480u, 0x114E0u)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
+- if (hb_in_range (u, 0x11580u, 0x115C8u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+- if (hb_in_range (u, 0x11600u, 0x116D0u)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
++ if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
++ if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
++ if (hb_in_range (u, 0x11280u, 0x11377u)) return indic_table[u - 0x11280u + indic_offset_0x11280u];
++ if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
++ if (hb_in_range (u, 0x11580u, 0x1173Fu)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+ break;
+
+ default:
+@@ -914,11 +962,14 @@
+ #undef ISC_CD
+ #undef ISC_CF
+ #undef ISC_CHL
++#undef ISC_CK
+ #undef ISC_CM
+ #undef ISC_CP
+ #undef ISC_CPR
++#undef ISC_CPrf
+ #undef ISC_CS
+ #undef ISC_CSR
++#undef ISC_CWS
+ #undef ISC_GM
+ #undef ISC_IS
+ #undef ISC_ZWJ
+@@ -930,6 +981,7 @@
+ #undef ISC_x
+ #undef ISC_PK
+ #undef ISC_RS
++#undef ISC_SM
+ #undef ISC_TL
+ #undef ISC_TM
+ #undef ISC_V
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-myanmar.cc gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-myanmar.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc 2016-06-05 23:50:00.982800449 +0200
+@@ -154,7 +154,7 @@
+ {
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+- return !!(FLAG (info.myanmar_category()) & flags);
++ return !!(FLAG_SAFE (info.myanmar_category()) & flags);
+ }
+
+ static inline bool
+@@ -199,6 +199,10 @@
+ cat = (indic_category_t) OT_A;
+ break;
+
++ case 0x1039u:
++ cat = (indic_category_t) OT_H;
++ break;
++
+ case 0x103Au:
+ cat = (indic_category_t) OT_As;
+ break;
+@@ -304,9 +308,7 @@
+ * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */
+
+ static void
+-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
++initial_reordering_consonant_syllable (hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+ {
+ hb_glyph_info_t *info = buffer->info;
+@@ -393,42 +395,10 @@
+ }
+ }
+
+- buffer->merge_clusters (start, end);
+ /* Sit tight, rock 'n roll! */
+- hb_bubble_sort (info + start, end - start, compare_myanmar_order);
+-}
+-
+-static void
+-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- /* We already inserted dotted-circles, so just call the consonant_syllable. */
+- initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+-}
+-
+-static void
+-initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_face_t *face HB_UNUSED,
+- hb_buffer_t *buffer HB_UNUSED,
+- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+-{
+- /* Nothing to do right now. If we ever switch to using the output
+- * buffer in the reordering process, we'd need to next_glyph() here. */
+-}
+-
+-static void
+-initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_face_t *face HB_UNUSED,
+- hb_buffer_t *buffer HB_UNUSED,
+- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+-{
+- /* Nothing to do right now. If we ever switch to using the output
+- * buffer in the reordering process, we'd need to next_glyph() here. */
++ buffer->sort (start, end, compare_myanmar_order);
+ }
+
+-
+ static void
+ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+@@ -437,10 +407,15 @@
+ {
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+ switch (syllable_type) {
+- case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+- case punctuation_cluster: initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return;
+- case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+- case non_myanmar_cluster: initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return;
++
++ case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
++ case consonant_syllable:
++ initial_reordering_consonant_syllable (buffer, start, end);
++ break;
++
++ case punctuation_cluster:
++ case non_myanmar_cluster:
++ break;
+ }
+ }
+
+@@ -484,12 +459,12 @@
+ {
+ last_syllable = syllable;
+
+- hb_glyph_info_t info = dottedcircle;
+- info.cluster = buffer->cur().cluster;
+- info.mask = buffer->cur().mask;
+- info.syllable() = buffer->cur().syllable();
++ hb_glyph_info_t ginfo = dottedcircle;
++ ginfo.cluster = buffer->cur().cluster;
++ ginfo.mask = buffer->cur().mask;
++ ginfo.syllable() = buffer->cur().syllable();
+
+- buffer->output_info (info);
++ buffer->output_info (ginfo);
+ }
+ else
+ buffer->next_glyph ();
+@@ -505,18 +480,8 @@
+ {
+ insert_dotted_circles (plan, font, buffer);
+
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int count = buffer->len;
+- if (unlikely (!count)) return;
+- unsigned int last = 0;
+- unsigned int last_syllable = info[0].syllable();
+- for (unsigned int i = 1; i < count; i++)
+- if (last_syllable != info[i].syllable()) {
+- initial_reordering_syllable (plan, font->face, buffer, last, i);
+- last = i;
+- last_syllable = info[last].syllable();
+- }
+- initial_reordering_syllable (plan, font->face, buffer, last, count);
++ foreach_syllable (buffer, start, end)
++ initial_reordering_syllable (plan, font->face, buffer, start, end);
+ }
+
+ static void
+@@ -546,6 +511,7 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+@@ -562,6 +528,7 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ NULL, /* decompose */
+ NULL, /* compose */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-myanmar-machine.hh gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-myanmar-machine.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh 2016-06-05 23:49:58.177815172 +0200
+@@ -1,5 +1,5 @@
+
+-#line 1 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
+ /*
+ * Copyright © 2011,2012 Google, Inc.
+ *
+@@ -32,7 +32,7 @@
+ #include "hb-private.hh"
+
+
+-#line 36 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
+ static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
+ 1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
+ 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
+@@ -261,11 +261,11 @@
+ static const int myanmar_syllable_machine_en_main = 0;
+
+
+-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
+
+
+
+-#line 93 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
+
+
+ #define found_syllable(syllable_type) \
+@@ -285,7 +285,7 @@
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+
+-#line 289 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 289 "hb-ot-shape-complex-myanmar-machine.hh"
+ {
+ cs = myanmar_syllable_machine_start;
+ ts = 0;
+@@ -293,7 +293,7 @@
+ act = 0;
+ }
+
+-#line 114 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
+
+
+ p = 0;
+@@ -302,7 +302,7 @@
+ unsigned int last = 0;
+ unsigned int syllable_serial = 1;
+
+-#line 306 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 306 "hb-ot-shape-complex-myanmar-machine.hh"
+ {
+ int _slen;
+ int _trans;
+@@ -316,7 +316,7 @@
+ #line 1 "NONE"
+ {ts = p;}
+ break;
+-#line 320 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
+ }
+
+ _keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
+@@ -335,38 +335,38 @@
+
+ switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
+ case 7:
+-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (consonant_syllable); }}
+ break;
+ case 5:
+-#line 86 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+ break;
+ case 10:
+-#line 87 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (punctuation_cluster); }}
+ break;
+ case 4:
+-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (broken_cluster); }}
+ break;
+ case 3:
+-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p+1;{ found_syllable (non_myanmar_cluster); }}
+ break;
+ case 6:
+-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (consonant_syllable); }}
+ break;
+ case 8:
+-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (broken_cluster); }}
+ break;
+ case 9:
+-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
+ {te = p;p--;{ found_syllable (non_myanmar_cluster); }}
+ break;
+-#line 370 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 370 "hb-ot-shape-complex-myanmar-machine.hh"
+ }
+
+ _again:
+@@ -375,7 +375,7 @@
+ #line 1 "NONE"
+ {ts = 0;}
+ break;
+-#line 379 "hb-ot-shape-complex-myanmar-machine.hh.tmp"
++#line 379 "hb-ot-shape-complex-myanmar-machine.hh"
+ }
+
+ if ( ++p != pe )
+@@ -391,7 +391,7 @@
+
+ }
+
+-#line 123 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
++#line 123 "hb-ot-shape-complex-myanmar-machine.rl"
+
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-private.hh gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-private.hh 2016-06-05 23:50:02.264793753 +0200
+@@ -44,9 +44,7 @@
+ // HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+-
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
+ };
+
+
+@@ -59,9 +57,9 @@
+ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
+- HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
++ HB_COMPLEX_SHAPER_IMPLEMENT (use) \
+ /* ^--- Add new shapers here */
+
+
+@@ -110,6 +108,15 @@
+ hb_buffer_t *buffer,
+ hb_font_t *font);
+
++ /* postprocess_glyphs()
++ * Called during shape().
++ * Shapers can use to modify glyphs after shaping ends.
++ * May be NULL.
++ */
++ void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer,
++ hb_font_t *font);
++
+
+ hb_ot_shape_normalization_mode_t normalization_preference;
+
+@@ -179,9 +186,12 @@
+ case HB_SCRIPT_PSALTER_PAHLAVI:
+
+ /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
+- * This is because we do fallback shaping for Arabic script (and not others). */
+- if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+- planner->props.script == HB_SCRIPT_ARABIC)
++ * This is because we do fallback shaping for Arabic script (and not others).
++ * But note that Arabic shaping is applicable only to horizontal layout; for
++ * vertical text, just use the generic shaper instead. */
++ if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
++ planner->props.script == HB_SCRIPT_ARABIC) &&
++ HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
+ return &_hb_ot_complex_shaper_arabic;
+ else
+ return &_hb_ot_complex_shaper_default;
+@@ -214,60 +224,9 @@
+
+ /* ^--- Add new shapers here */
+
+-
+ #if 0
+- /* Note:
+- *
+- * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according
+- * to Martin Hosken and Jonathan Kew do not require complex shaping.
+- *
+- * TODO We should automate figuring out which scripts do not need complex shaping
+- *
+- * TODO We currently keep data for these scripts in our indic table. Need to fix the
+- * generator to not do that.
+- */
+-
+-
+- /* Simple? */
+-
+- /* Unicode-3.2 additions */
+- case HB_SCRIPT_BUHID:
+- case HB_SCRIPT_HANUNOO:
+-
+- /* Unicode-5.1 additions */
+- case HB_SCRIPT_SAURASHTRA:
+-
+- /* Unicode-6.0 additions */
+- case HB_SCRIPT_BATAK:
+- case HB_SCRIPT_BRAHMI:
+-
+-
+- /* Simple */
+-
+- /* Unicode-1.1 additions */
+- /* These have their own shaper now. */
+- case HB_SCRIPT_LAO:
+- case HB_SCRIPT_THAI:
+-
+- /* Unicode-3.2 additions */
+- case HB_SCRIPT_TAGALOG:
+- case HB_SCRIPT_TAGBANWA:
+-
+- /* Unicode-4.0 additions */
+- case HB_SCRIPT_LIMBU:
+- case HB_SCRIPT_TAI_LE:
+-
+ /* Unicode-4.1 additions */
+- case HB_SCRIPT_KHAROSHTHI:
+- case HB_SCRIPT_SYLOTI_NAGRI:
+-
+- /* Unicode-5.1 additions */
+- case HB_SCRIPT_KAYAH_LI:
+-
+- /* Unicode-5.2 additions */
+- case HB_SCRIPT_TAI_VIET:
+-
+-
++ case HB_SCRIPT_NEW_TAI_LUE:
+ #endif
+
+ /* Unicode-1.1 additions */
+@@ -284,28 +243,11 @@
+ /* Unicode-3.0 additions */
+ case HB_SCRIPT_SINHALA:
+
+- /* Unicode-5.0 additions */
+- case HB_SCRIPT_BALINESE:
+-
+- /* Unicode-5.1 additions */
+- case HB_SCRIPT_LEPCHA:
+- case HB_SCRIPT_REJANG:
+- case HB_SCRIPT_SUNDANESE:
+-
+ /* Unicode-5.2 additions */
+ case HB_SCRIPT_JAVANESE:
+- case HB_SCRIPT_KAITHI:
+- case HB_SCRIPT_MEETEI_MAYEK:
+-
+- /* Unicode-6.0 additions */
+-
+- /* Unicode-6.1 additions */
+- case HB_SCRIPT_CHAKMA:
+- case HB_SCRIPT_SHARADA:
+- case HB_SCRIPT_TAKRI:
+
+ /* If the designer designed the font for the 'DFLT' script,
+- * use the default shaper. Otherwise, use the Indic shaper.
++ * use the default shaper. Otherwise, use the specific shaper.
+ * Note that for some simple scripts, there may not be *any*
+ * GSUB/GPOS needed, so there may be no scripts found! */
+ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+@@ -337,24 +279,82 @@
+ else
+ return &_hb_ot_complex_shaper_default;
+
++
++ /* Unicode-2.0 additions */
++ //case HB_SCRIPT_TIBETAN:
++
++ /* Unicode-3.0 additions */
++ //case HB_SCRIPT_MONGOLIAN:
++ //case HB_SCRIPT_SINHALA:
++
++ /* Unicode-3.2 additions */
++ case HB_SCRIPT_BUHID:
++ case HB_SCRIPT_HANUNOO:
++ case HB_SCRIPT_TAGALOG:
++ case HB_SCRIPT_TAGBANWA:
++
++ /* Unicode-4.0 additions */
++ case HB_SCRIPT_LIMBU:
++ case HB_SCRIPT_TAI_LE:
++
+ /* Unicode-4.1 additions */
+ case HB_SCRIPT_BUGINESE:
+- case HB_SCRIPT_NEW_TAI_LUE:
++ case HB_SCRIPT_KHAROSHTHI:
++ case HB_SCRIPT_SYLOTI_NAGRI:
++ case HB_SCRIPT_TIFINAGH:
++
++ /* Unicode-5.0 additions */
++ case HB_SCRIPT_BALINESE:
++ //case HB_SCRIPT_NKO:
++ //case HB_SCRIPT_PHAGS_PA:
+
+ /* Unicode-5.1 additions */
+ case HB_SCRIPT_CHAM:
++ case HB_SCRIPT_KAYAH_LI:
++ case HB_SCRIPT_LEPCHA:
++ case HB_SCRIPT_REJANG:
++ case HB_SCRIPT_SAURASHTRA:
++ case HB_SCRIPT_SUNDANESE:
+
+ /* Unicode-5.2 additions */
++ case HB_SCRIPT_EGYPTIAN_HIEROGLYPHS:
++ //case HB_SCRIPT_JAVANESE:
++ case HB_SCRIPT_KAITHI:
++ case HB_SCRIPT_MEETEI_MAYEK:
+ case HB_SCRIPT_TAI_THAM:
++ case HB_SCRIPT_TAI_VIET:
++
++ /* Unicode-6.0 additions */
++ case HB_SCRIPT_BATAK:
++ case HB_SCRIPT_BRAHMI:
++ //case HB_SCRIPT_MANDAIC:
++
++ /* Unicode-6.1 additions */
++ case HB_SCRIPT_CHAKMA:
++ case HB_SCRIPT_SHARADA:
++ case HB_SCRIPT_TAKRI:
++
++ /* Unicode-7.0 additions */
++ case HB_SCRIPT_DUPLOYAN:
++ case HB_SCRIPT_GRANTHA:
++ case HB_SCRIPT_KHOJKI:
++ case HB_SCRIPT_KHUDAWADI:
++ case HB_SCRIPT_MAHAJANI:
++ //case HB_SCRIPT_MANICHAEAN:
++ case HB_SCRIPT_MODI:
++ case HB_SCRIPT_PAHAWH_HMONG:
++ //case HB_SCRIPT_PSALTER_PAHLAVI:
++ case HB_SCRIPT_SIDDHAM:
++ case HB_SCRIPT_TIRHUTA:
+
+ /* If the designer designed the font for the 'DFLT' script,
+- * use the default shaper. Otherwise, use the Indic shaper.
++ * use the default shaper. Otherwise, use the specific shaper.
+ * Note that for some simple scripts, there may not be *any*
+ * GSUB/GPOS needed, so there may be no scripts found! */
+ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+ return &_hb_ot_complex_shaper_default;
+ else
+- return &_hb_ot_complex_shaper_sea;
++ return &_hb_ot_complex_shaper_use;
+ }
+ }
+
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-sea.cc gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-sea.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc 1970-01-01 01:00:00.000000000 +0100
+@@ -1,380 +0,0 @@
+-/*
+- * Copyright © 2011,2012,2013 Google, Inc.
+- *
+- * This is part of HarfBuzz, a text shaping library.
+- *
+- * Permission is hereby granted, without written agreement and without
+- * license or royalty fees, to use, copy, modify, and distribute this
+- * software and its documentation for any purpose, provided that the
+- * above copyright notice and the following two paragraphs appear in
+- * all copies of this software.
+- *
+- * 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-ot-shape-complex-indic-private.hh"
+-
+-/* buffer var allocations */
+-#define sea_category() complex_var_u8_0() /* indic_category_t */
+-#define sea_position() complex_var_u8_1() /* indic_position_t */
+-
+-
+-/*
+- * South-East Asian shaper.
+- * Loosely based on the Myanmar spec / shaper.
+- * There is no OpenType spec for this.
+- */
+-
+-static const hb_tag_t
+-basic_features[] =
+-{
+- /*
+- * Basic features.
+- * These features are applied in order, one at a time, after initial_reordering.
+- */
+- HB_TAG('p','r','e','f'),
+- HB_TAG('a','b','v','f'),
+- HB_TAG('b','l','w','f'),
+- HB_TAG('p','s','t','f'),
+-};
+-static const hb_tag_t
+-other_features[] =
+-{
+- /*
+- * Other features.
+- * These features are applied all at once, after final_reordering.
+- */
+- HB_TAG('p','r','e','s'),
+- HB_TAG('a','b','v','s'),
+- HB_TAG('b','l','w','s'),
+- HB_TAG('p','s','t','s'),
+- /* Positioning features, though we don't care about the types. */
+- HB_TAG('d','i','s','t'),
+-};
+-
+-static void
+-setup_syllables (const hb_ot_shape_plan_t *plan,
+- hb_font_t *font,
+- hb_buffer_t *buffer);
+-static void
+-initial_reordering (const hb_ot_shape_plan_t *plan,
+- hb_font_t *font,
+- hb_buffer_t *buffer);
+-static void
+-final_reordering (const hb_ot_shape_plan_t *plan,
+- hb_font_t *font,
+- hb_buffer_t *buffer);
+-
+-static void
+-collect_features_sea (hb_ot_shape_planner_t *plan)
+-{
+- hb_ot_map_builder_t *map = &plan->map;
+-
+- /* Do this before any lookups have been applied. */
+- map->add_gsub_pause (setup_syllables);
+-
+- map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+- /* The Indic specs do not require ccmp, but we apply it here since if
+- * there is a use of it, it's typically at the beginning. */
+- map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+-
+- map->add_gsub_pause (initial_reordering);
+- for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+- {
+- map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+- map->add_gsub_pause (NULL);
+- }
+- map->add_gsub_pause (final_reordering);
+- for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+- map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+-}
+-
+-static void
+-override_features_sea (hb_ot_shape_planner_t *plan)
+-{
+- plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+-}
+-
+-
+-enum syllable_type_t {
+- consonant_syllable,
+- broken_cluster,
+- non_sea_cluster,
+-};
+-
+-#include "hb-ot-shape-complex-sea-machine.hh"
+-
+-
+-/* Note: This enum is duplicated in the -machine.rl source file.
+- * Not sure how to avoid duplication. */
+-enum sea_category_t {
+-// OT_C = 1,
+- OT_GB = 12, /* Generic Base XXX DOTTED CIRCLE only for now */
+-// OT_H = 4, /* Halant */
+- OT_IV = 2, /* Independent Vowel */
+- OT_MR = 22, /* Medial Ra */
+-// OT_CM = 17, /* Consonant Medial */
+- OT_VAbv = 26,
+- OT_VBlw = 27,
+- OT_VPre = 28,
+- OT_VPst = 29,
+- OT_T = 3, /* Tone Marks */
+-// OT_A = 10, /* Anusvara */
+-};
+-
+-static inline void
+-set_sea_properties (hb_glyph_info_t &info)
+-{
+- hb_codepoint_t u = info.codepoint;
+- unsigned int type = hb_indic_get_categories (u);
+- indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+- indic_position_t pos = (indic_position_t) (type >> 8);
+-
+- /* Medial Ra */
+- if (u == 0x1A55u || u == 0xAA34u)
+- cat = (indic_category_t) OT_MR;
+-
+- if (cat == OT_M)
+- {
+- switch ((int) pos)
+- {
+- case POS_PRE_C: cat = (indic_category_t) OT_VPre; break;
+- case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break;
+- case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break;
+- case POS_POST_C: cat = (indic_category_t) OT_VPst; break;
+- }
+- }
+-
+- info.sea_category() = (sea_category_t) cat;
+- info.sea_position() = pos;
+-}
+-
+-
+-static void
+-setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_buffer_t *buffer,
+- hb_font_t *font HB_UNUSED)
+-{
+- HB_BUFFER_ALLOCATE_VAR (buffer, sea_category);
+- HB_BUFFER_ALLOCATE_VAR (buffer, sea_position);
+-
+- /* We cannot setup masks here. We save information about characters
+- * and setup masks later on in a pause-callback. */
+-
+- unsigned int count = buffer->len;
+- hb_glyph_info_t *info = buffer->info;
+- for (unsigned int i = 0; i < count; i++)
+- set_sea_properties (info[i]);
+-}
+-
+-static void
+-setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_font_t *font HB_UNUSED,
+- hb_buffer_t *buffer)
+-{
+- find_syllables (buffer);
+-}
+-
+-static int
+-compare_sea_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+-{
+- int a = pa->sea_position();
+- int b = pb->sea_position();
+-
+- return a < b ? -1 : a == b ? 0 : +1;
+-}
+-
+-
+-static void
+-initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int base = start;
+-
+- /* Reorder! */
+- unsigned int i = start;
+- for (; i < base; i++)
+- info[i].sea_position() = POS_PRE_C;
+- if (i < end)
+- {
+- info[i].sea_position() = POS_BASE_C;
+- i++;
+- }
+- for (; i < end; i++)
+- {
+- if (info[i].sea_category() == OT_MR) /* Pre-base reordering */
+- {
+- info[i].sea_position() = POS_PRE_C;
+- continue;
+- }
+- if (info[i].sea_category() == OT_VPre) /* Left matra */
+- {
+- info[i].sea_position() = POS_PRE_M;
+- continue;
+- }
+-
+- info[i].sea_position() = POS_AFTER_MAIN;
+- }
+-
+- buffer->merge_clusters (start, end);
+- /* Sit tight, rock 'n roll! */
+- hb_bubble_sort (info + start, end - start, compare_sea_order);
+-}
+-
+-static void
+-initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- /* We already inserted dotted-circles, so just call the consonant_syllable. */
+- initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+-}
+-
+-static void
+-initial_reordering_non_sea_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_face_t *face HB_UNUSED,
+- hb_buffer_t *buffer HB_UNUSED,
+- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+-{
+- /* Nothing to do right now. If we ever switch to using the output
+- * buffer in the reordering process, we'd need to next_glyph() here. */
+-}
+-
+-
+-static void
+-initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+- hb_face_t *face,
+- hb_buffer_t *buffer,
+- unsigned int start, unsigned int end)
+-{
+- syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+- switch (syllable_type) {
+- case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+- case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+- case non_sea_cluster: initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return;
+- }
+-}
+-
+-static inline void
+-insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+- hb_font_t *font,
+- hb_buffer_t *buffer)
+-{
+- /* Note: This loop is extra overhead, but should not be measurable. */
+- bool has_broken_syllables = false;
+- unsigned int count = buffer->len;
+- hb_glyph_info_t *info = buffer->info;
+- for (unsigned int i = 0; i < count; i++)
+- if ((info[i].syllable() & 0x0F) == broken_cluster)
+- {
+- has_broken_syllables = true;
+- break;
+- }
+- if (likely (!has_broken_syllables))
+- return;
+-
+-
+- hb_codepoint_t dottedcircle_glyph;
+- if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+- return;
+-
+- hb_glyph_info_t dottedcircle = {0};
+- dottedcircle.codepoint = 0x25CCu;
+- set_sea_properties (dottedcircle);
+- dottedcircle.codepoint = dottedcircle_glyph;
+-
+- buffer->clear_output ();
+-
+- buffer->idx = 0;
+- unsigned int last_syllable = 0;
+- while (buffer->idx < buffer->len)
+- {
+- unsigned int syllable = buffer->cur().syllable();
+- syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+- if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+- {
+- last_syllable = syllable;
+-
+- hb_glyph_info_t info = dottedcircle;
+- info.cluster = buffer->cur().cluster;
+- info.mask = buffer->cur().mask;
+- info.syllable() = buffer->cur().syllable();
+-
+- buffer->output_info (info);
+- }
+- else
+- buffer->next_glyph ();
+- }
+-
+- buffer->swap_buffers ();
+-}
+-
+-static void
+-initial_reordering (const hb_ot_shape_plan_t *plan,
+- hb_font_t *font,
+- hb_buffer_t *buffer)
+-{
+- insert_dotted_circles (plan, font, buffer);
+-
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int count = buffer->len;
+- if (unlikely (!count)) return;
+- unsigned int last = 0;
+- unsigned int last_syllable = info[0].syllable();
+- for (unsigned int i = 1; i < count; i++)
+- if (last_syllable != info[i].syllable()) {
+- initial_reordering_syllable (plan, font->face, buffer, last, i);
+- last = i;
+- last_syllable = info[last].syllable();
+- }
+- initial_reordering_syllable (plan, font->face, buffer, last, count);
+-}
+-
+-static void
+-final_reordering (const hb_ot_shape_plan_t *plan,
+- hb_font_t *font HB_UNUSED,
+- hb_buffer_t *buffer)
+-{
+- hb_glyph_info_t *info = buffer->info;
+- unsigned int count = buffer->len;
+-
+- /* Zero syllables now... */
+- for (unsigned int i = 0; i < count; i++)
+- info[i].syllable() = 0;
+-
+- HB_BUFFER_DEALLOCATE_VAR (buffer, sea_category);
+- HB_BUFFER_DEALLOCATE_VAR (buffer, sea_position);
+-}
+-
+-
+-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
+-{
+- "sea",
+- collect_features_sea,
+- override_features_sea,
+- NULL, /* data_create */
+- NULL, /* data_destroy */
+- NULL, /* preprocess_text */
+- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+- NULL, /* decompose */
+- NULL, /* compose */
+- setup_masks_sea,
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+- false, /* fallback_position */
+-};
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-sea-machine.hh gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-sea-machine.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh 1970-01-01 01:00:00.000000000 +0100
+@@ -1,224 +0,0 @@
+-
+-#line 1 "../../src/hb-ot-shape-complex-sea-machine.rl"
+-/*
+- * Copyright © 2011,2012,2013 Google, Inc.
+- *
+- * This is part of HarfBuzz, a text shaping library.
+- *
+- * Permission is hereby granted, without written agreement and without
+- * license or royalty fees, to use, copy, modify, and distribute this
+- * software and its documentation for any purpose, provided that the
+- * above copyright notice and the following two paragraphs appear in
+- * all copies of this software.
+- *
+- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+- * DAMAGE.
+- *
+- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+- *
+- * Google Author(s): Behdad Esfahbod
+- */
+-
+-#ifndef HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+-#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+-
+-#include "hb-private.hh"
+-
+-
+-#line 36 "hb-ot-shape-complex-sea-machine.hh.tmp"
+-static const unsigned char _sea_syllable_machine_trans_keys[] = {
+- 1u, 1u, 1u, 1u, 1u, 29u, 3u, 29u, 3u, 29u, 1u, 1u, 0
+-};
+-
+-static const char _sea_syllable_machine_key_spans[] = {
+- 1, 1, 29, 27, 27, 1
+-};
+-
+-static const char _sea_syllable_machine_index_offsets[] = {
+- 0, 2, 4, 34, 62, 90
+-};
+-
+-static const char _sea_syllable_machine_indicies[] = {
+- 1, 0, 3, 2, 1, 1, 3, 5,
+- 4, 4, 4, 4, 4, 3, 4, 1,
+- 4, 4, 4, 4, 3, 4, 4, 4,
+- 4, 3, 4, 4, 4, 3, 3, 3,
+- 3, 4, 1, 7, 6, 6, 6, 6,
+- 6, 1, 6, 6, 6, 6, 6, 6,
+- 1, 6, 6, 6, 6, 1, 6, 6,
+- 6, 1, 1, 1, 1, 6, 3, 9,
+- 8, 8, 8, 8, 8, 3, 8, 8,
+- 8, 8, 8, 8, 3, 8, 8, 8,
+- 8, 3, 8, 8, 8, 3, 3, 3,
+- 3, 8, 3, 10, 0
+-};
+-
+-static const char _sea_syllable_machine_trans_targs[] = {
+- 2, 3, 2, 4, 2, 5, 2, 0,
+- 2, 1, 2
+-};
+-
+-static const char _sea_syllable_machine_trans_actions[] = {
+- 1, 2, 3, 2, 6, 0, 7, 0,
+- 8, 0, 9
+-};
+-
+-static const char _sea_syllable_machine_to_state_actions[] = {
+- 0, 0, 4, 0, 0, 0
+-};
+-
+-static const char _sea_syllable_machine_from_state_actions[] = {
+- 0, 0, 5, 0, 0, 0
+-};
+-
+-static const char _sea_syllable_machine_eof_trans[] = {
+- 1, 3, 0, 7, 9, 11
+-};
+-
+-static const int sea_syllable_machine_start = 2;
+-static const int sea_syllable_machine_first_final = 2;
+-static const int sea_syllable_machine_error = -1;
+-
+-static const int sea_syllable_machine_en_main = 2;
+-
+-
+-#line 36 "../../src/hb-ot-shape-complex-sea-machine.rl"
+-
+-
+-
+-#line 67 "../../src/hb-ot-shape-complex-sea-machine.rl"
+-
+-
+-#define found_syllable(syllable_type) \
+- HB_STMT_START { \
+- if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+- for (unsigned int i = last; i < p+1; i++) \
+- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+- last = p+1; \
+- syllable_serial++; \
+- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+- } HB_STMT_END
+-
+-static void
+-find_syllables (hb_buffer_t *buffer)
+-{
+- unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+- int cs;
+- hb_glyph_info_t *info = buffer->info;
+-
+-#line 117 "hb-ot-shape-complex-sea-machine.hh.tmp"
+- {
+- cs = sea_syllable_machine_start;
+- ts = 0;
+- te = 0;
+- act = 0;
+- }
+-
+-#line 88 "../../src/hb-ot-shape-complex-sea-machine.rl"
+-
+-
+- p = 0;
+- pe = eof = buffer->len;
+-
+- unsigned int last = 0;
+- unsigned int syllable_serial = 1;
+-
+-#line 134 "hb-ot-shape-complex-sea-machine.hh.tmp"
+- {
+- int _slen;
+- int _trans;
+- const unsigned char *_keys;
+- const char *_inds;
+- if ( p == pe )
+- goto _test_eof;
+-_resume:
+- switch ( _sea_syllable_machine_from_state_actions[cs] ) {
+- case 5:
+-#line 1 "NONE"
+- {ts = p;}
+- break;
+-#line 148 "hb-ot-shape-complex-sea-machine.hh.tmp"
+- }
+-
+- _keys = _sea_syllable_machine_trans_keys + (cs<<1);
+- _inds = _sea_syllable_machine_indicies + _sea_syllable_machine_index_offsets[cs];
+-
+- _slen = _sea_syllable_machine_key_spans[cs];
+- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].sea_category()) &&
+- ( info[p].sea_category()) <= _keys[1] ?
+- ( info[p].sea_category()) - _keys[0] : _slen ];
+-
+-_eof_trans:
+- cs = _sea_syllable_machine_trans_targs[_trans];
+-
+- if ( _sea_syllable_machine_trans_actions[_trans] == 0 )
+- goto _again;
+-
+- switch ( _sea_syllable_machine_trans_actions[_trans] ) {
+- case 2:
+-#line 1 "NONE"
+- {te = p+1;}
+- break;
+- case 6:
+-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {te = p+1;{ found_syllable (non_sea_cluster); }}
+- break;
+- case 7:
+-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {te = p;p--;{ found_syllable (consonant_syllable); }}
+- break;
+- case 8:
+-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {te = p;p--;{ found_syllable (broken_cluster); }}
+- break;
+- case 9:
+-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {te = p;p--;{ found_syllable (non_sea_cluster); }}
+- break;
+- case 1:
+-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
+- break;
+- case 3:
+-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
+- {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
+- break;
+-#line 194 "hb-ot-shape-complex-sea-machine.hh.tmp"
+- }
+-
+-_again:
+- switch ( _sea_syllable_machine_to_state_actions[cs] ) {
+- case 4:
+-#line 1 "NONE"
+- {ts = 0;}
+- break;
+-#line 203 "hb-ot-shape-complex-sea-machine.hh.tmp"
+- }
+-
+- if ( ++p != pe )
+- goto _resume;
+- _test_eof: {}
+- if ( p == eof )
+- {
+- if ( _sea_syllable_machine_eof_trans[cs] > 0 ) {
+- _trans = _sea_syllable_machine_eof_trans[cs] - 1;
+- goto _eof_trans;
+- }
+- }
+-
+- }
+-
+-#line 97 "../../src/hb-ot-shape-complex-sea-machine.rl"
+-
+-}
+-
+-#undef found_syllable
+-
+-#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-sea-machine.rl gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-sea-machine.rl 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl 1970-01-01 01:00:00.000000000 +0100
+@@ -1,102 +0,0 @@
+-/*
+- * Copyright © 2011,2012,2013 Google, Inc.
+- *
+- * This is part of HarfBuzz, a text shaping library.
+- *
+- * Permission is hereby granted, without written agreement and without
+- * license or royalty fees, to use, copy, modify, and distribute this
+- * software and its documentation for any purpose, provided that the
+- * above copyright notice and the following two paragraphs appear in
+- * all copies of this software.
+- *
+- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+- * DAMAGE.
+- *
+- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+- *
+- * Google Author(s): Behdad Esfahbod
+- */
+-
+-#ifndef HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+-#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+-
+-#include "hb-private.hh"
+-
+-%%{
+- machine sea_syllable_machine;
+- alphtype unsigned char;
+- write data;
+-}%%
+-
+-%%{
+-
+-# Same order as enum sea_category_t. Not sure how to avoid duplication.
+-C = 1;
+-GB = 12; # Generic Base
+-H = 4; # Halant
+-IV = 2; # Independent Vowel
+-MR = 22; # Medial Ra
+-CM = 17; # Consonant Medial
+-VAbv = 26;
+-VBlw = 27;
+-VPre = 28;
+-VPst = 29;
+-T = 3; # Tone Marks
+-A = 10; # Anusvara
+-
+-syllable_tail = (VPre|VAbv|VBlw|VPst|H.C|CM|MR|T|A)*;
+-
+-consonant_syllable = (C|IV|GB) syllable_tail;
+-broken_cluster = syllable_tail;
+-other = any;
+-
+-main := |*
+- consonant_syllable => { found_syllable (consonant_syllable); };
+- broken_cluster => { found_syllable (broken_cluster); };
+- other => { found_syllable (non_sea_cluster); };
+-*|;
+-
+-
+-}%%
+-
+-#define found_syllable(syllable_type) \
+- HB_STMT_START { \
+- if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+- for (unsigned int i = last; i < p+1; i++) \
+- info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+- last = p+1; \
+- syllable_serial++; \
+- if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+- } HB_STMT_END
+-
+-static void
+-find_syllables (hb_buffer_t *buffer)
+-{
+- unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+- int cs;
+- hb_glyph_info_t *info = buffer->info;
+- %%{
+- write init;
+- getkey info[p].sea_category();
+- }%%
+-
+- p = 0;
+- pe = eof = buffer->len;
+-
+- unsigned int last = 0;
+- unsigned int syllable_serial = 1;
+- %%{
+- write exec;
+- }%%
+-}
+-
+-#undef found_syllable
+-
+-#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-thai.cc gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-thai.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc 2016-06-05 23:50:03.390787882 +0200
+@@ -139,7 +139,7 @@
+ };
+
+ switch (action) {
+- default: assert (false); /* Fallthrough */
++ default: assert (false); HB_FALLTHROUGH;
+ case NOP: return u;
+ case SD: pua_mappings = SD_mappings; break;
+ case SDL: pua_mappings = SDL_mappings; break;
+@@ -315,7 +315,7 @@
+
+ buffer->clear_output ();
+ unsigned int count = buffer->len;
+- for (buffer->idx = 0; buffer->idx < count;)
++ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+ {
+ hb_codepoint_t u = buffer->cur().codepoint;
+ if (likely (!IS_SARA_AM (u))) {
+@@ -330,7 +330,7 @@
+ if (unlikely (buffer->in_error))
+ return;
+
+- /* Make Nikhahit be recognized as a mark when zeroing widths. */
++ /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
+ unsigned int end = buffer->out_len;
+ _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
+
+@@ -353,7 +353,7 @@
+ {
+ /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
+ * previous cluster. */
+- if (start)
++ if (start && buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+ buffer->merge_out_clusters (start - 1, end);
+ }
+ }
+@@ -372,10 +372,11 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ preprocess_text_thai,
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ false,/* fallback_position */
+ };
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-tibetan.cc gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-tibetan.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc 2016-06-05 23:50:04.665781201 +0200
+@@ -52,10 +52,11 @@
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ true, /* fallback_position */
+ };
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-use.cc gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-use.cc 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-use.cc 2016-06-05 23:50:11.851743709 +0200
+@@ -0,0 +1,588 @@
++/*
++ * Copyright © 2015 Mozilla Foundation.
++ * Copyright © 2015 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.
++ *
++ * Mozilla Author(s): Jonathan Kew
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#include "hb-ot-shape-complex-use-private.hh"
++#include "hb-ot-shape-complex-arabic-private.hh"
++
++/* buffer var allocations */
++#define use_category() complex_var_u8_0()
++
++
++/*
++ * Universal Shaping Engine.
++ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
++ */
++
++static const hb_tag_t
++basic_features[] =
++{
++ /*
++ * Basic features.
++ * These features are applied all at once, before reordering.
++ */
++ HB_TAG('r','k','r','f'),
++ HB_TAG('a','b','v','f'),
++ HB_TAG('b','l','w','f'),
++ HB_TAG('h','a','l','f'),
++ HB_TAG('p','s','t','f'),
++ HB_TAG('v','a','t','u'),
++ HB_TAG('c','j','c','t'),
++};
++static const hb_tag_t
++arabic_features[] =
++{
++ HB_TAG('i','s','o','l'),
++ HB_TAG('i','n','i','t'),
++ HB_TAG('m','e','d','i'),
++ HB_TAG('f','i','n','a'),
++ /* The spec doesn't specify these but we apply anyway, since our Arabic shaper
++ * does. These are only used in Syriac spec. */
++ HB_TAG('m','e','d','2'),
++ HB_TAG('f','i','n','2'),
++ HB_TAG('f','i','n','3'),
++};
++/* Same order as arabic_features. Don't need Syriac stuff.*/
++enum joining_form_t {
++ ISOL,
++ INIT,
++ MEDI,
++ FINA,
++ _NONE
++};
++static const hb_tag_t
++other_features[] =
++{
++ /*
++ * Other features.
++ * These features are applied all at once, after reordering.
++ */
++ HB_TAG('a','b','v','s'),
++ HB_TAG('b','l','w','s'),
++ HB_TAG('h','a','l','n'),
++ HB_TAG('p','r','e','s'),
++ HB_TAG('p','s','t','s'),
++ /* Positioning features, though we don't care about the types. */
++ HB_TAG('d','i','s','t'),
++ HB_TAG('a','b','v','m'),
++ HB_TAG('b','l','w','m'),
++};
++
++static void
++setup_syllables (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++static void
++clear_substitution_flags (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++static void
++record_rphf (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++static void
++record_pref (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++static void
++reorder (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++
++static void
++collect_features_use (hb_ot_shape_planner_t *plan)
++{
++ hb_ot_map_builder_t *map = &plan->map;
++
++ /* Do this before any lookups have been applied. */
++ map->add_gsub_pause (setup_syllables);
++
++ /* "Default glyph pre-processing group" */
++ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
++ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
++ map->add_global_bool_feature (HB_TAG('n','u','k','t'));
++ map->add_global_bool_feature (HB_TAG('a','k','h','n'));
++
++ /* "Reordering group" */
++ map->add_gsub_pause (clear_substitution_flags);
++ map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ);
++ map->add_gsub_pause (record_rphf);
++ map->add_gsub_pause (clear_substitution_flags);
++ map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ);
++ map->add_gsub_pause (record_pref);
++
++ /* "Orthographic unit shaping group" */
++ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
++ map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
++
++ map->add_gsub_pause (reorder);
++
++ /* "Topographical features" */
++ for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
++ map->add_feature (arabic_features[i], 1, F_NONE);
++ map->add_gsub_pause (NULL);
++
++ /* "Standard typographic presentation" and "Positional feature application" */
++ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
++ map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
++}
++
++struct use_shape_plan_t
++{
++ ASSERT_POD ();
++
++ hb_mask_t rphf_mask;
++
++ arabic_shape_plan_t *arabic_plan;
++};
++
++static bool
++has_arabic_joining (hb_script_t script)
++{
++ /* List of scripts that have data in arabic-table. */
++ switch ((int) script)
++ {
++ /* Unicode-1.1 additions */
++ case HB_SCRIPT_ARABIC:
++
++ /* Unicode-3.0 additions */
++ case HB_SCRIPT_MONGOLIAN:
++ case HB_SCRIPT_SYRIAC:
++
++ /* Unicode-5.0 additions */
++ case HB_SCRIPT_NKO:
++ case HB_SCRIPT_PHAGS_PA:
++
++ /* Unicode-6.0 additions */
++ case HB_SCRIPT_MANDAIC:
++
++ /* Unicode-7.0 additions */
++ case HB_SCRIPT_MANICHAEAN:
++ case HB_SCRIPT_PSALTER_PAHLAVI:
++
++ return true;
++
++ default:
++ return false;
++ }
++}
++
++static void *
++data_create_use (const hb_ot_shape_plan_t *plan)
++{
++ use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
++ if (unlikely (!use_plan))
++ return NULL;
++
++ use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));
++
++ if (has_arabic_joining (plan->props.script))
++ {
++ use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
++ if (unlikely (!use_plan->arabic_plan))
++ {
++ free (use_plan);
++ return NULL;
++ }
++ }
++
++ return use_plan;
++}
++
++static void
++data_destroy_use (void *data)
++{
++ use_shape_plan_t *use_plan = (use_shape_plan_t *) data;
++
++ if (use_plan->arabic_plan)
++ data_destroy_arabic (use_plan->arabic_plan);
++
++ free (data);
++}
++
++enum syllable_type_t {
++ independent_cluster,
++ virama_terminated_cluster,
++ consonant_cluster,
++ vowel_cluster,
++ number_joiner_terminated_cluster,
++ numeral_cluster,
++ symbol_cluster,
++ broken_cluster,
++};
++
++#include "hb-ot-shape-complex-use-machine.hh"
++
++
++static void
++setup_masks_use (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer,
++ hb_font_t *font HB_UNUSED)
++{
++ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
++
++ /* Do this before allocating use_category(). */
++ if (use_plan->arabic_plan)
++ {
++ setup_masks_arabic_plan (use_plan->arabic_plan, buffer, plan->props.script);
++ }
++
++ HB_BUFFER_ALLOCATE_VAR (buffer, use_category);
++
++ /* We cannot setup masks here. We save information about characters
++ * and setup masks later on in a pause-callback. */
++
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ for (unsigned int i = 0; i < count; i++)
++ info[i].use_category() = hb_use_get_categories (info[i].codepoint);
++}
++
++static void
++setup_rphf_mask (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer)
++{
++ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
++
++ hb_mask_t mask = use_plan->rphf_mask;
++ if (!mask) return;
++
++ hb_glyph_info_t *info = buffer->info;
++
++ foreach_syllable (buffer, start, end)
++ {
++ unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start);
++ for (unsigned int i = start; i < start + limit; i++)
++ info[i].mask |= mask;
++ }
++}
++
++static void
++setup_topographical_masks (const hb_ot_shape_plan_t *plan,
++ hb_buffer_t *buffer)
++{
++ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
++ if (use_plan->arabic_plan)
++ return;
++
++ ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
++ hb_mask_t masks[4], all_masks = 0;
++ for (unsigned int i = 0; i < 4; i++)
++ {
++ masks[i] = plan->map.get_1_mask (arabic_features[i]);
++ if (masks[i] == plan->map.get_global_mask ())
++ masks[i] = 0;
++ all_masks |= masks[i];
++ }
++ if (!all_masks)
++ return;
++ hb_mask_t other_masks = ~all_masks;
++
++ unsigned int last_start = 0;
++ joining_form_t last_form = _NONE;
++ hb_glyph_info_t *info = buffer->info;
++ foreach_syllable (buffer, start, end)
++ {
++ syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F);
++ switch (syllable_type)
++ {
++ case independent_cluster:
++ case symbol_cluster:
++ /* These don't join. Nothing to do. */
++ last_form = _NONE;
++ break;
++
++ case virama_terminated_cluster:
++ case consonant_cluster:
++ case vowel_cluster:
++ case number_joiner_terminated_cluster:
++ case numeral_cluster:
++ case broken_cluster:
++
++ bool join = last_form == FINA || last_form == ISOL;
++
++ if (join)
++ {
++ /* Fixup previous syllable's form. */
++ last_form = last_form == FINA ? MEDI : INIT;
++ for (unsigned int i = last_start; i < start; i++)
++ info[i].mask = (info[i].mask & other_masks) | masks[last_form];
++ }
++
++ /* Form for this syllable. */
++ last_form = join ? FINA : ISOL;
++ for (unsigned int i = start; i < end; i++)
++ info[i].mask = (info[i].mask & other_masks) | masks[last_form];
++
++ break;
++ }
++
++ last_start = start;
++ }
++}
++
++static void
++setup_syllables (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font HB_UNUSED,
++ hb_buffer_t *buffer)
++{
++ find_syllables (buffer);
++ setup_rphf_mask (plan, buffer);
++ setup_topographical_masks (plan, buffer);
++}
++
++static void
++clear_substitution_flags (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font HB_UNUSED,
++ hb_buffer_t *buffer)
++{
++ hb_glyph_info_t *info = buffer->info;
++ unsigned int count = buffer->len;
++ for (unsigned int i = 0; i < count; i++)
++ _hb_glyph_info_clear_substituted (&info[i]);
++}
++
++static void
++record_rphf (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
++
++ hb_mask_t mask = use_plan->rphf_mask;
++ if (!mask) return;
++ hb_glyph_info_t *info = buffer->info;
++
++ foreach_syllable (buffer, start, end)
++ {
++ /* Mark a substituted repha as USE_R. */
++ for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
++ if (_hb_glyph_info_substituted (&info[i]))
++ {
++ info[i].use_category() = USE_R;
++ break;
++ }
++ }
++}
++
++static void
++record_pref (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ hb_glyph_info_t *info = buffer->info;
++
++ foreach_syllable (buffer, start, end)
++ {
++ /* Mark a substituted pref as VPre, as they behave the same way. */
++ for (unsigned int i = start; i < end; i++)
++ if (_hb_glyph_info_substituted (&info[i]))
++ {
++ info[i].use_category() = USE_VPre;
++ break;
++ }
++ }
++}
++
++static inline bool
++is_halant (const hb_glyph_info_t &info)
++{
++ return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
++}
++
++static void
++reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
++{
++ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
++ /* Only a few syllable types need reordering. */
++ if (unlikely (!(FLAG_SAFE (syllable_type) &
++ (FLAG (virama_terminated_cluster) |
++ FLAG (consonant_cluster) |
++ FLAG (vowel_cluster) |
++ FLAG (broken_cluster) |
++ 0))))
++ return;
++
++ hb_glyph_info_t *info = buffer->info;
++
++#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB) | FLAG (USE_IV))
++
++ /* Move things forward. */
++ if (info[start].use_category() == USE_R && end - start > 1)
++ {
++ /* Got a repha. Reorder it to after first base, before first halant. */
++ for (unsigned int i = start + 1; i < end; i++)
++ if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i]))
++ {
++ /* If we hit a halant, move before it; otherwise it's a base: move to it's
++ * place, and shift things in between backward. */
++
++ if (is_halant (info[i]))
++ i--;
++
++ buffer->merge_clusters (start, i + 1);
++ hb_glyph_info_t t = info[start];
++ memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
++ info[i] = t;
++
++ break;
++ }
++ }
++
++ /* Move things back. */
++ unsigned int j = end;
++ for (unsigned int i = start; i < end; i++)
++ {
++ uint32_t flag = FLAG_UNSAFE (info[i].use_category());
++ if ((flag & (BASE_FLAGS)) || is_halant (info[i]))
++ {
++ /* If we hit a halant, move after it; otherwise it's a base: move to it's
++ * place, and shift things in between backward. */
++ if (is_halant (info[i]))
++ j = i + 1;
++ else
++ j = i;
++ }
++ else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
++ /* Only move the first component of a MultipleSubst. */
++ 0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
++ j < i)
++ {
++ buffer->merge_clusters (j, i + 1);
++ hb_glyph_info_t t = info[i];
++ memmove (&info[j + 1], &info[j], (i - j) * sizeof (info[0]));
++ info[j] = t;
++ }
++ }
++}
++
++static inline void
++insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ /* Note: This loop is extra overhead, but should not be measurable. */
++ bool has_broken_syllables = false;
++ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
++ for (unsigned int i = 0; i < count; i++)
++ if ((info[i].syllable() & 0x0F) == broken_cluster)
++ {
++ has_broken_syllables = true;
++ break;
++ }
++ if (likely (!has_broken_syllables))
++ return;
++
++ hb_glyph_info_t dottedcircle = {0};
++ if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
++ return;
++ dottedcircle.use_category() = hb_use_get_categories (0x25CC);
++
++ buffer->clear_output ();
++
++ buffer->idx = 0;
++ unsigned int last_syllable = 0;
++ while (buffer->idx < buffer->len && !buffer->in_error)
++ {
++ unsigned int syllable = buffer->cur().syllable();
++ syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
++ if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
++ {
++ last_syllable = syllable;
++
++ hb_glyph_info_t ginfo = dottedcircle;
++ ginfo.cluster = buffer->cur().cluster;
++ ginfo.mask = buffer->cur().mask;
++ ginfo.syllable() = buffer->cur().syllable();
++ /* TODO Set glyph_props? */
++
++ /* Insert dottedcircle after possible Repha. */
++ while (buffer->idx < buffer->len &&
++ last_syllable == buffer->cur().syllable() &&
++ buffer->cur().use_category() == USE_R)
++ buffer->next_glyph ();
++
++ buffer->output_info (ginfo);
++ }
++ else
++ buffer->next_glyph ();
++ }
++
++ buffer->swap_buffers ();
++}
++
++static void
++reorder (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ insert_dotted_circles (plan, font, buffer);
++
++ hb_glyph_info_t *info = buffer->info;
++
++ foreach_syllable (buffer, start, end)
++ reorder_syllable (buffer, start, end);
++
++ /* Zero syllables now... */
++ unsigned int count = buffer->len;
++ for (unsigned int i = 0; i < count; i++)
++ info[i].syllable() = 0;
++
++ HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
++}
++
++static bool
++compose_use (const hb_ot_shape_normalize_context_t *c,
++ hb_codepoint_t a,
++ hb_codepoint_t b,
++ hb_codepoint_t *ab)
++{
++ /* Avoid recomposing split matras. */
++ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
++ return false;
++
++ return (bool)c->unicode->compose (a, b, ab);
++}
++
++
++const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
++{
++ "use",
++ collect_features_use,
++ NULL, /* override_features */
++ data_create_use,
++ data_destroy_use,
++ NULL, /* preprocess_text */
++ NULL, /* postprocess_glyphs */
++ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
++ NULL, /* decompose */
++ compose_use,
++ setup_masks_use,
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
++ false, /* fallback_position */
++};
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-use-machine.hh gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-use-machine.hh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.hh 2016-06-05 23:50:06.101773685 +0200
+@@ -0,0 +1,548 @@
++
++#line 1 "hb-ot-shape-complex-use-machine.rl"
++/*
++ * Copyright © 2015 Mozilla Foundation.
++ * Copyright © 2015 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.
++ *
++ * Mozilla Author(s): Jonathan Kew
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
++#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
++
++#include "hb-private.hh"
++
++
++#line 38 "hb-ot-shape-complex-use-machine.hh"
++static const unsigned char _use_syllable_machine_trans_keys[] = {
++ 0u, 0u, 4u, 4u, 1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u,
++ 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u,
++ 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
++ 8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u,
++ 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
++ 8u, 39u, 12u, 21u, 12u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u,
++ 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
++ 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u,
++ 42u, 42u, 0
++};
++
++static const char _use_syllable_machine_key_spans[] = {
++ 0, 1, 1, 40, 1, 32, 32, 1,
++ 32, 32, 32, 19, 19, 19, 32, 32,
++ 32, 32, 32, 32, 32, 32, 32, 32,
++ 32, 32, 32, 1, 32, 32, 19, 19,
++ 19, 32, 32, 32, 32, 32, 32, 32,
++ 32, 10, 2, 32, 32, 32, 32, 19,
++ 19, 19, 32, 32, 32, 32, 32, 32,
++ 32, 32, 32, 32, 39, 32, 22, 2,
++ 1
++};
++
++static const short _use_syllable_machine_index_offsets[] = {
++ 0, 0, 2, 4, 45, 47, 80, 113,
++ 115, 148, 181, 214, 234, 254, 274, 307,
++ 340, 373, 406, 439, 472, 505, 538, 571,
++ 604, 637, 670, 703, 705, 738, 771, 791,
++ 811, 831, 864, 897, 930, 963, 996, 1029,
++ 1062, 1095, 1106, 1109, 1142, 1175, 1208, 1241,
++ 1261, 1281, 1301, 1334, 1367, 1400, 1433, 1466,
++ 1499, 1532, 1565, 1598, 1631, 1671, 1704, 1727,
++ 1730
++};
++
++static const char _use_syllable_machine_indicies[] = {
++ 1, 0, 3, 2, 4, 5, 6,
++ 4, 1, 5, 8, 8, 7, 8, 8,
++ 3, 9, 8, 8, 8, 4, 4, 10,
++ 11, 8, 8, 12, 13, 14, 15, 16,
++ 17, 18, 12, 19, 20, 21, 22, 23,
++ 24, 8, 25, 26, 27, 8, 29, 28,
++ 31, 30, 30, 32, 33, 30, 30, 30,
++ 30, 30, 30, 30, 30, 34, 35, 36,
++ 37, 38, 39, 40, 41, 35, 42, 34,
++ 43, 44, 45, 46, 30, 47, 48, 49,
++ 30, 31, 30, 30, 32, 33, 30, 30,
++ 30, 30, 30, 30, 30, 30, 50, 35,
++ 36, 37, 38, 39, 40, 41, 35, 42,
++ 43, 43, 44, 45, 46, 30, 47, 48,
++ 49, 30, 32, 51, 31, 30, 30, 32,
++ 33, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 35, 36, 37, 38, 39, 40,
++ 41, 35, 42, 43, 43, 44, 45, 46,
++ 30, 47, 48, 49, 30, 31, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 35, 36, 37, 38, 39,
++ 30, 30, 30, 30, 30, 30, 44, 45,
++ 46, 30, 47, 48, 49, 30, 31, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 36, 37, 38,
++ 39, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 47, 48, 49, 30, 31,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 37,
++ 38, 39, 30, 31, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 38, 39, 30, 31,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 39, 30, 31, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 37, 38, 39, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 47, 48, 49, 30, 31, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 37, 38, 39, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 48, 49, 30, 31, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 37, 38, 39,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 49, 30, 31, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 36, 37, 38,
++ 39, 30, 30, 30, 30, 30, 30, 44,
++ 45, 46, 30, 47, 48, 49, 30, 31,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 36, 37,
++ 38, 39, 30, 30, 30, 30, 30, 30,
++ 30, 45, 46, 30, 47, 48, 49, 30,
++ 31, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 36,
++ 37, 38, 39, 30, 30, 30, 30, 30,
++ 30, 30, 30, 46, 30, 47, 48, 49,
++ 30, 31, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 35,
++ 36, 37, 38, 39, 30, 41, 35, 30,
++ 30, 30, 44, 45, 46, 30, 47, 48,
++ 49, 30, 31, 30, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 35, 36, 37, 38, 39, 30, 30, 35,
++ 30, 30, 30, 44, 45, 46, 30, 47,
++ 48, 49, 30, 31, 30, 30, 30, 30,
++ 30, 30, 30, 30, 30, 30, 30, 30,
++ 30, 35, 36, 37, 38, 39, 40, 41,
++ 35, 30, 30, 30, 44, 45, 46, 30,
++ 47, 48, 49, 30, 31, 30, 30, 32,
++ 33, 30, 30, 30, 30, 30, 30, 30,
++ 30, 30, 35, 36, 37, 38, 39, 40,
++ 41, 35, 42, 30, 43, 44, 45, 46,
++ 30, 47, 48, 49, 30, 31, 30, 30,
++ 32, 33, 30, 30, 30, 30, 30, 30,
++ 30, 30, 30, 35, 36, 37, 38, 39,
++ 40, 41, 35, 42, 34, 43, 44, 45,
++ 46, 30, 47, 48, 49, 30, 53, 52,
++ 52, 54, 55, 52, 52, 52, 52, 52,
++ 52, 52, 52, 56, 52, 57, 58, 59,
++ 60, 61, 62, 57, 63, 56, 64, 52,
++ 52, 52, 52, 65, 66, 67, 52, 53,
++ 52, 52, 54, 55, 52, 52, 52, 52,
++ 52, 52, 52, 52, 68, 52, 57, 58,
++ 59, 60, 61, 62, 57, 63, 64, 64,
++ 52, 52, 52, 52, 65, 66, 67, 52,
++ 54, 51, 53, 52, 52, 54, 55, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 57, 58, 59, 60, 61, 62, 57,
++ 63, 64, 64, 52, 52, 52, 52, 65,
++ 66, 67, 52, 53, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 57, 58, 59, 60, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 65, 66, 67, 52, 53, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 58, 59, 60, 52,
++ 53, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 59, 60, 52, 53, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 60, 52,
++ 53, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 58, 59, 60, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 65, 66, 67,
++ 52, 53, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 58, 59, 60, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 66,
++ 67, 52, 53, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 58, 59, 60, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 67, 52, 53, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 57, 58, 59, 60, 52, 62,
++ 57, 52, 52, 52, 52, 52, 52, 52,
++ 65, 66, 67, 52, 53, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 57, 58, 59, 60, 52,
++ 52, 57, 52, 52, 52, 52, 52, 52,
++ 52, 65, 66, 67, 52, 53, 52, 52,
++ 52, 52, 52, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 57, 58, 59, 60,
++ 61, 62, 57, 52, 52, 52, 52, 52,
++ 52, 52, 65, 66, 67, 52, 53, 52,
++ 52, 54, 55, 52, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 57, 58, 59,
++ 60, 61, 62, 57, 63, 52, 64, 52,
++ 52, 52, 52, 65, 66, 67, 52, 53,
++ 52, 52, 54, 55, 52, 52, 52, 52,
++ 52, 52, 52, 52, 52, 52, 57, 58,
++ 59, 60, 61, 62, 57, 63, 56, 64,
++ 52, 52, 52, 52, 65, 66, 67, 52,
++ 70, 71, 69, 69, 69, 69, 69, 69,
++ 69, 72, 69, 70, 71, 69, 7, 73,
++ 73, 3, 9, 73, 73, 73, 73, 73,
++ 73, 73, 73, 74, 12, 13, 14, 15,
++ 16, 17, 18, 12, 19, 21, 21, 22,
++ 23, 24, 73, 25, 26, 27, 73, 7,
++ 73, 73, 3, 9, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 12, 13, 14,
++ 15, 16, 17, 18, 12, 19, 21, 21,
++ 22, 23, 24, 73, 25, 26, 27, 73,
++ 7, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 12, 13,
++ 14, 15, 16, 73, 73, 73, 73, 73,
++ 73, 22, 23, 24, 73, 25, 26, 27,
++ 73, 7, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 13, 14, 15, 16, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 25, 26,
++ 27, 73, 7, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 14, 15, 16, 73, 7, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 15,
++ 16, 73, 7, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 16, 73, 7, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 14, 15,
++ 16, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 25, 26, 27, 73, 7,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 14,
++ 15, 16, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 26, 27, 73,
++ 7, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 14, 15, 16, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 27,
++ 73, 7, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 13, 14, 15, 16, 73, 73, 73, 73,
++ 73, 73, 22, 23, 24, 73, 25, 26,
++ 27, 73, 7, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 13, 14, 15, 16, 73, 73, 73,
++ 73, 73, 73, 73, 23, 24, 73, 25,
++ 26, 27, 73, 7, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 13, 14, 15, 16, 73, 73,
++ 73, 73, 73, 73, 73, 73, 24, 73,
++ 25, 26, 27, 73, 7, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 12, 13, 14, 15, 16, 73,
++ 18, 12, 73, 73, 73, 22, 23, 24,
++ 73, 25, 26, 27, 73, 7, 73, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 12, 13, 14, 15, 16,
++ 73, 73, 12, 73, 73, 73, 22, 23,
++ 24, 73, 25, 26, 27, 73, 7, 73,
++ 73, 73, 73, 73, 73, 73, 73, 73,
++ 73, 73, 73, 73, 12, 13, 14, 15,
++ 16, 17, 18, 12, 73, 73, 73, 22,
++ 23, 24, 73, 25, 26, 27, 73, 7,
++ 73, 73, 3, 9, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 12, 13, 14,
++ 15, 16, 17, 18, 12, 19, 73, 21,
++ 22, 23, 24, 73, 25, 26, 27, 73,
++ 5, 6, 73, 73, 5, 73, 73, 7,
++ 73, 73, 3, 9, 73, 73, 73, 73,
++ 73, 73, 73, 73, 73, 12, 13, 14,
++ 15, 16, 17, 18, 12, 19, 20, 21,
++ 22, 23, 24, 73, 25, 26, 27, 73,
++ 7, 73, 73, 3, 9, 73, 73, 73,
++ 73, 73, 73, 73, 73, 73, 12, 13,
++ 14, 15, 16, 17, 18, 12, 19, 20,
++ 21, 22, 23, 24, 73, 25, 26, 27,
++ 73, 76, 75, 75, 75, 75, 75, 75,
++ 75, 75, 75, 75, 75, 75, 75, 75,
++ 75, 75, 75, 75, 75, 76, 77, 75,
++ 76, 77, 75, 77, 75, 0
++};
++
++static const char _use_syllable_machine_trans_targs[] = {
++ 3, 41, 3, 43, 4, 5, 25, 3,
++ 0, 2, 60, 62, 45, 46, 47, 48,
++ 49, 56, 57, 58, 61, 59, 53, 54,
++ 55, 50, 51, 52, 3, 3, 3, 3,
++ 6, 7, 24, 9, 10, 11, 12, 13,
++ 20, 21, 22, 23, 17, 18, 19, 14,
++ 15, 16, 8, 3, 3, 3, 26, 27,
++ 40, 29, 30, 31, 32, 36, 37, 38,
++ 39, 33, 34, 35, 28, 3, 3, 1,
++ 42, 3, 44, 3, 63, 64
++};
++
++static const char _use_syllable_machine_trans_actions[] = {
++ 1, 2, 3, 4, 0, 0, 0, 7,
++ 0, 0, 4, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 4, 4, 0, 0,
++ 0, 0, 0, 0, 8, 9, 10, 11,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 12, 13, 14, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 15, 16, 0,
++ 2, 17, 4, 18, 0, 0
++};
++
++static const char _use_syllable_machine_to_state_actions[] = {
++ 0, 0, 0, 5, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0
++};
++
++static const char _use_syllable_machine_from_state_actions[] = {
++ 0, 0, 0, 6, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 0
++};
++
++static const short _use_syllable_machine_eof_trans[] = {
++ 0, 1, 3, 0, 29, 31, 31, 52,
++ 31, 31, 31, 31, 31, 31, 31, 31,
++ 31, 31, 31, 31, 31, 31, 31, 31,
++ 31, 53, 53, 52, 53, 53, 53, 53,
++ 53, 53, 53, 53, 53, 53, 53, 53,
++ 53, 70, 70, 74, 74, 74, 74, 74,
++ 74, 74, 74, 74, 74, 74, 74, 74,
++ 74, 74, 74, 74, 74, 74, 76, 76,
++ 76
++};
++
++static const int use_syllable_machine_start = 3;
++static const int use_syllable_machine_first_final = 3;
++static const int use_syllable_machine_error = 0;
++
++static const int use_syllable_machine_en_main = 3;
++
++
++#line 38 "hb-ot-shape-complex-use-machine.rl"
++
++
++
++#line 145 "hb-ot-shape-complex-use-machine.rl"
++
++
++#define found_syllable(syllable_type) \
++ HB_STMT_START { \
++ if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
++ for (unsigned int i = last; i < p+1; i++) \
++ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
++ last = p+1; \
++ syllable_serial++; \
++ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
++ } HB_STMT_END
++
++static void
++find_syllables (hb_buffer_t *buffer)
++{
++ unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
++ int cs;
++ hb_glyph_info_t *info = buffer->info;
++
++#line 388 "hb-ot-shape-complex-use-machine.hh"
++ {
++ cs = use_syllable_machine_start;
++ ts = 0;
++ te = 0;
++ act = 0;
++ }
++
++#line 166 "hb-ot-shape-complex-use-machine.rl"
++
++
++ p = 0;
++ pe = eof = buffer->len;
++
++ unsigned int last = 0;
++ unsigned int syllable_serial = 1;
++
++#line 405 "hb-ot-shape-complex-use-machine.hh"
++ {
++ int _slen;
++ int _trans;
++ const unsigned char *_keys;
++ const char *_inds;
++ if ( p == pe )
++ goto _test_eof;
++ if ( cs == 0 )
++ goto _out;
++_resume:
++ switch ( _use_syllable_machine_from_state_actions[cs] ) {
++ case 6:
++#line 1 "NONE"
++ {ts = p;}
++ break;
++#line 421 "hb-ot-shape-complex-use-machine.hh"
++ }
++
++ _keys = _use_syllable_machine_trans_keys + (cs<<1);
++ _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs];
++
++ _slen = _use_syllable_machine_key_spans[cs];
++ _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].use_category()) &&
++ ( info[p].use_category()) <= _keys[1] ?
++ ( info[p].use_category()) - _keys[0] : _slen ];
++
++_eof_trans:
++ cs = _use_syllable_machine_trans_targs[_trans];
++
++ if ( _use_syllable_machine_trans_actions[_trans] == 0 )
++ goto _again;
++
++ switch ( _use_syllable_machine_trans_actions[_trans] ) {
++ case 2:
++#line 1 "NONE"
++ {te = p+1;}
++ break;
++ case 9:
++#line 134 "hb-ot-shape-complex-use-machine.rl"
++ {te = p+1;{ found_syllable (independent_cluster); }}
++ break;
++ case 11:
++#line 136 "hb-ot-shape-complex-use-machine.rl"
++ {te = p+1;{ found_syllable (consonant_cluster); }}
++ break;
++ case 14:
++#line 137 "hb-ot-shape-complex-use-machine.rl"
++ {te = p+1;{ found_syllable (vowel_cluster); }}
++ break;
++ case 16:
++#line 138 "hb-ot-shape-complex-use-machine.rl"
++ {te = p+1;{ found_syllable (number_joiner_terminated_cluster); }}
++ break;
++ case 7:
++#line 141 "hb-ot-shape-complex-use-machine.rl"
++ {te = p+1;{ found_syllable (broken_cluster); }}
++ break;
++ case 8:
++#line 134 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (independent_cluster); }}
++ break;
++ case 12:
++#line 135 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (virama_terminated_cluster); }}
++ break;
++ case 10:
++#line 136 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (consonant_cluster); }}
++ break;
++ case 13:
++#line 137 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (vowel_cluster); }}
++ break;
++ case 15:
++#line 139 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (numeral_cluster); }}
++ break;
++ case 18:
++#line 140 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (symbol_cluster); }}
++ break;
++ case 17:
++#line 141 "hb-ot-shape-complex-use-machine.rl"
++ {te = p;p--;{ found_syllable (broken_cluster); }}
++ break;
++ case 1:
++#line 139 "hb-ot-shape-complex-use-machine.rl"
++ {{p = ((te))-1;}{ found_syllable (numeral_cluster); }}
++ break;
++ case 3:
++#line 1 "NONE"
++ { switch( act ) {
++ case 0:
++ {{cs = 0; goto _again;}}
++ break;
++ case 8:
++ {{p = ((te))-1;} found_syllable (broken_cluster); }
++ break;
++ }
++ }
++ break;
++ case 4:
++#line 1 "NONE"
++ {te = p+1;}
++#line 141 "hb-ot-shape-complex-use-machine.rl"
++ {act = 8;}
++ break;
++#line 513 "hb-ot-shape-complex-use-machine.hh"
++ }
++
++_again:
++ switch ( _use_syllable_machine_to_state_actions[cs] ) {
++ case 5:
++#line 1 "NONE"
++ {ts = 0;}
++#line 1 "NONE"
++ {act = 0;}
++ break;
++#line 524 "hb-ot-shape-complex-use-machine.hh"
++ }
++
++ if ( cs == 0 )
++ goto _out;
++ if ( ++p != pe )
++ goto _resume;
++ _test_eof: {}
++ if ( p == eof )
++ {
++ if ( _use_syllable_machine_eof_trans[cs] > 0 ) {
++ _trans = _use_syllable_machine_eof_trans[cs] - 1;
++ goto _eof_trans;
++ }
++ }
++
++ _out: {}
++ }
++
++#line 175 "hb-ot-shape-complex-use-machine.rl"
++
++}
++
++#undef found_syllable
++
++#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-use-machine.rl gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.rl
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-use-machine.rl 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-use-machine.rl 2016-06-05 23:50:07.357767129 +0200
+@@ -0,0 +1,180 @@
++/*
++ * Copyright © 2015 Mozilla Foundation.
++ * Copyright © 2015 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.
++ *
++ * Mozilla Author(s): Jonathan Kew
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
++#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
++
++#include "hb-private.hh"
++
++%%{
++ machine use_syllable_machine;
++ alphtype unsigned char;
++ write data;
++}%%
++
++%%{
++
++# Same order as enum use_category_t. Not sure how to avoid duplication.
++
++O = 0; # OTHER
++
++B = 1; # BASE
++IV = 2; # BASE_VOWEL
++IND = 3; # BASE_IND
++N = 4; # BASE_NUM
++GB = 5; # BASE_OTHER
++CGJ = 6; # CGJ
++#F = 7; # CONS_FINAL
++FM = 8; # CONS_FINAL_MOD
++#M = 9; # CONS_MED
++#CM = 10; # CONS_MOD
++SUB = 11; # CONS_SUB
++H = 12; # HALANT
++
++HN = 13; # HALANT_NUM
++ZWNJ = 14; # Zero width non-joiner
++ZWJ = 15; # Zero width joiner
++WJ = 16; # Word joiner
++Rsv = 17; # Reserved characters
++R = 18; # REPHA
++S = 19; # SYM
++#SM = 20; # SYM_MOD
++VS = 21; # VARIATION_SELECTOR
++#V = 36; # VOWEL
++#VM = 40; # VOWEL_MOD
++
++FAbv = 24; # CONS_FINAL_ABOVE
++FBlw = 25; # CONS_FINAL_BELOW
++FPst = 26; # CONS_FINAL_POST
++MAbv = 27; # CONS_MED_ABOVE
++MBlw = 28; # CONS_MED_BELOW
++MPst = 29; # CONS_MED_POST
++MPre = 30; # CONS_MED_PRE
++CMAbv = 31; # CONS_MOD_ABOVE
++CMBlw = 32; # CONS_MOD_BELOW
++VAbv = 33; # VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST
++VBlw = 34; # VOWEL_BELOW / VOWEL_BELOW_POST
++VPst = 35; # VOWEL_POST UIPC = Right
++VPre = 22; # VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST
++VMAbv = 37; # VOWEL_MOD_ABOVE
++VMBlw = 38; # VOWEL_MOD_BELOW
++VMPst = 39; # VOWEL_MOD_POST
++VMPre = 23; # VOWEL_MOD_PRE
++SMAbv = 41; # SYM_MOD_ABOVE
++SMBlw = 42; # SYM_MOD_BELOW
++
++
++consonant_modifiers = CMAbv* CMBlw* ((H B | SUB) VS? CMAbv? CMBlw*)*;
++medial_consonants = MPre? MAbv? MBlw? MPst?;
++dependent_vowels = VPre* VAbv* VBlw* VPst*;
++vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*;
++final_consonants = FAbv* FBlw* FPst* FM?;
++
++virama_terminated_cluster =
++ R? (B | GB | IV) VS?
++ consonant_modifiers
++ H
++;
++consonant_cluster =
++ R? (B | GB) VS?
++ consonant_modifiers
++ medial_consonants
++ dependent_vowels
++ vowel_modifiers
++ final_consonants
++;
++vowel_cluster =
++ R? (IV) VS?
++ consonant_modifiers
++ medial_consonants
++ vowel_modifiers
++ final_consonants
++;
++
++broken_cluster =
++ R?
++ consonant_modifiers
++ medial_consonants
++ dependent_vowels
++ vowel_modifiers
++ final_consonants
++;
++
++number_joiner_terminated_cluster = N VS? (HN N VS?)* H;
++numeral_cluster = N VS? (HN N VS?)*;
++symbol_cluster = S VS? SMAbv* SMBlw*;
++independent_cluster = (IND | O | Rsv | WJ) VS?;
++
++main := |*
++ independent_cluster => { found_syllable (independent_cluster); };
++ virama_terminated_cluster => { found_syllable (virama_terminated_cluster); };
++ consonant_cluster => { found_syllable (consonant_cluster); };
++ vowel_cluster => { found_syllable (vowel_cluster); };
++ number_joiner_terminated_cluster => { found_syllable (number_joiner_terminated_cluster); };
++ numeral_cluster => { found_syllable (numeral_cluster); };
++ symbol_cluster => { found_syllable (symbol_cluster); };
++ broken_cluster => { found_syllable (broken_cluster); };
++*|;
++
++
++}%%
++
++#define found_syllable(syllable_type) \
++ HB_STMT_START { \
++ if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
++ for (unsigned int i = last; i < p+1; i++) \
++ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
++ last = p+1; \
++ syllable_serial++; \
++ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
++ } HB_STMT_END
++
++static void
++find_syllables (hb_buffer_t *buffer)
++{
++ unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
++ int cs;
++ hb_glyph_info_t *info = buffer->info;
++ %%{
++ write init;
++ getkey info[p].use_category();
++ }%%
++
++ p = 0;
++ pe = eof = buffer->len;
++
++ unsigned int last = 0;
++ unsigned int syllable_serial = 1;
++ %%{
++ write exec;
++ }%%
++}
++
++#undef found_syllable
++
++#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-use-private.hh gfx/harfbuzz/src/hb-ot-shape-complex-use-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-use-private.hh 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-use-private.hh 2016-06-05 23:50:08.571760803 +0200
+@@ -0,0 +1,97 @@
++/*
++ * Copyright © 2015 Mozilla Foundation.
++ * Copyright © 2015 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.
++ *
++ * Mozilla Author(s): Jonathan Kew
++ * Google Author(s): Behdad Esfahbod
++ */
++
++#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
++#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
++
++#include "hb-private.hh"
++
++
++#include "hb-ot-shape-complex-private.hh"
++
++
++#define USE_TABLE_ELEMENT_TYPE uint8_t
++
++/* Cateories used in the Universal Shaping Engine spec:
++ * https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
++ */
++/* Note: This enum is duplicated in the -machine.rl source file.
++ * Not sure how to avoid duplication. */
++enum use_category_t {
++ USE_O = 0, /* OTHER */
++
++ USE_B = 1, /* BASE */
++ USE_IV = 2, /* BASE_VOWEL */
++ USE_IND = 3, /* BASE_IND */
++ USE_N = 4, /* BASE_NUM */
++ USE_GB = 5, /* BASE_OTHER */
++ USE_CGJ = 6, /* CGJ */
++// USE_F = 7, /* CONS_FINAL */
++ USE_FM = 8, /* CONS_FINAL_MOD */
++// USE_M = 9, /* CONS_MED */
++// USE_CM = 10, /* CONS_MOD */
++ USE_SUB = 11, /* CONS_SUB */
++ USE_H = 12, /* HALANT */
++
++ USE_HN = 13, /* HALANT_NUM */
++ USE_ZWNJ = 14, /* Zero width non-joiner */
++ USE_ZWJ = 15, /* Zero width joiner */
++ USE_WJ = 16, /* Word joiner */
++ USE_Rsv = 17, /* Reserved characters */
++ USE_R = 18, /* REPHA */
++ USE_S = 19, /* SYM */
++// USE_SM = 20, /* SYM_MOD */
++ USE_VS = 21, /* VARIATION_SELECTOR */
++// USE_V = 36, /* VOWEL */
++// USE_VM = 40, /* VOWEL_MOD */
++
++ USE_FAbv = 24, /* CONS_FINAL_ABOVE */
++ USE_FBlw = 25, /* CONS_FINAL_BELOW */
++ USE_FPst = 26, /* CONS_FINAL_POST */
++ USE_MAbv = 27, /* CONS_MED_ABOVE */
++ USE_MBlw = 28, /* CONS_MED_BELOW */
++ USE_MPst = 29, /* CONS_MED_POST */
++ USE_MPre = 30, /* CONS_MED_PRE */
++ USE_CMAbv = 31, /* CONS_MOD_ABOVE */
++ USE_CMBlw = 32, /* CONS_MOD_BELOW */
++ USE_VAbv = 33, /* VOWEL_ABOVE / VOWEL_ABOVE_BELOW / VOWEL_ABOVE_BELOW_POST / VOWEL_ABOVE_POST */
++ USE_VBlw = 34, /* VOWEL_BELOW / VOWEL_BELOW_POST */
++ USE_VPst = 35, /* VOWEL_POST UIPC = Right */
++ USE_VPre = 22, /* VOWEL_PRE / VOWEL_PRE_ABOVE / VOWEL_PRE_ABOVE_POST / VOWEL_PRE_POST */
++ USE_VMAbv = 37, /* VOWEL_MOD_ABOVE */
++ USE_VMBlw = 38, /* VOWEL_MOD_BELOW */
++ USE_VMPst = 39, /* VOWEL_MOD_POST */
++ USE_VMPre = 23, /* VOWEL_MOD_PRE */
++ USE_SMAbv = 41, /* SYM_MOD_ABOVE */
++ USE_SMBlw = 42 /* SYM_MOD_BELOW */
++};
++
++HB_INTERNAL USE_TABLE_ELEMENT_TYPE
++hb_use_get_categories (hb_codepoint_t u);
++
++#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-complex-use-table.cc gfx/harfbuzz/src/hb-ot-shape-complex-use-table.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-complex-use-table.cc 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/hb-ot-shape-complex-use-table.cc 2016-06-05 23:50:10.313751710 +0200
+@@ -0,0 +1,696 @@
++/* == Start of generated table == */
++/*
++ * The following table is generated by running:
++ *
++ * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
++ *
++ * on files with these headers:
++ *
++ * # IndicSyllabicCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # IndicPositionalCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # Blocks-8.0.0.txt
++ * # Date: 2014-11-10, 23:04:00 GMT [KW]
++ * UnicodeData.txt does not have a header.
++ */
++
++#include "hb-ot-shape-complex-use-private.hh"
++
++#define B USE_B /* BASE */
++#define CGJ USE_CGJ /* CGJ */
++#define FM USE_FM /* CONS_FINAL_MOD */
++#define GB USE_GB /* BASE_OTHER */
++#define H USE_H /* HALANT */
++#define HN USE_HN /* HALANT_NUM */
++#define IND USE_IND /* BASE_IND */
++#define IV USE_IV /* BASE_VOWEL */
++#define N USE_N /* BASE_NUM */
++#define O USE_O /* OTHER */
++#define R USE_R /* REPHA */
++#define Rsv USE_Rsv /* Reserved */
++#define S USE_S /* SYM */
++#define SUB USE_SUB /* CONS_SUB */
++#define VS USE_VS /* VARIATION_SELECTOR */
++#define WJ USE_WJ /* Word_Joiner */
++#define ZWJ USE_ZWJ /* ZWJ */
++#define ZWNJ USE_ZWNJ /* ZWNJ */
++#define CMBlw USE_CMBlw
++#define CMAbv USE_CMAbv
++#define FBlw USE_FBlw
++#define FPst USE_FPst
++#define FAbv USE_FAbv
++#define MPre USE_MPre
++#define MBlw USE_MBlw
++#define MPst USE_MPst
++#define MAbv USE_MAbv
++#define SMBlw USE_SMBlw
++#define SMAbv USE_SMAbv
++#define VPre USE_VPre
++#define VBlw USE_VBlw
++#define VPst USE_VPst
++#define VAbv USE_VAbv
++#define VMPre USE_VMPre
++#define VMBlw USE_VMBlw
++#define VMPst USE_VMPst
++#define VMAbv USE_VMAbv
++
++static const USE_TABLE_ELEMENT_TYPE use_table[] = {
++
++
++#define use_offset_0x0028u 0
++
++
++ /* Basic Latin */
++ O, O, O, O, O, GB, O, O,
++ /* 0030 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++#define use_offset_0x00a0u 24
++
++
++ /* Latin-1 Supplement */
++
++ /* 00A0 */ GB, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 00B0 */ O, O, FM, FM, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 00C0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 00D0 */ O, O, O, O, O, O, O, GB,
++
++#define use_offset_0x0900u 80
++
++
++ /* Devanagari */
++
++ /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 0910 */ IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0930 */ B, B, B, B, B, B, B, B, B, B, VAbv, VPst, CMBlw, B, VPst, VPre,
++ /* 0940 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst, H, VPre, VPst,
++ /* 0950 */ O, VMAbv, VMBlw, O, O, VAbv, VBlw, VBlw, B, B, B, B, B, B, B, B,
++ /* 0960 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0970 */ O, O, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B,
++
++ /* Bengali */
++
++ /* 0980 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
++ /* 0990 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
++ /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, IND, O,
++ /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B,
++ /* 09E0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Gurmukhi */
++
++ /* 0A00 */ O, VMAbv, VMAbv, VMPst, O, IV, IV, IV, IV, IV, IV, O, O, O, O, IV,
++ /* 0A10 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0A20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 0A30 */ B, O, B, B, O, B, B, O, B, B, O, O, CMBlw, O, VPst, VPre,
++ /* 0A40 */ VPst, VBlw, VBlw, O, O, O, O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O,
++ /* 0A50 */ O, O, O, O, O, O, O, O, O, B, B, B, B, O, B, O,
++ /* 0A60 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0A70 */ VMAbv, CMAbv, GB, GB, O, MBlw, O, O, O, O, O, O, O, O, O, O,
++
++ /* Gujarati */
++
++ /* 0A80 */ O, VMAbv, VMAbv, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, IV, O, IV,
++ /* 0A90 */ IV, IV, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0AA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 0AB0 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
++ /* 0AC0 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H, O, O,
++ /* 0AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 0AE0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0AF0 */ O, O, O, O, O, O, O, O, O, B, O, O, O, O, O, O,
++
++ /* Oriya */
++
++ /* 0B00 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
++ /* 0B10 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
++ /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
++ /* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B,
++ /* 0B60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Tamil */
++
++ /* 0B80 */ O, O, VMAbv, IND, O, IV, IV, IV, IV, IV, IV, O, O, O, IV, IV,
++ /* 0B90 */ IV, O, IV, IV, IV, B, O, O, O, B, B, O, B, O, B, B,
++ /* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B,
++ /* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst,
++ /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O,
++ /* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O,
++ /* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Telugu */
++
++ /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
++ /* 0C10 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0C20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 0C30 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, VAbv, VAbv,
++ /* 0C40 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
++ /* 0C50 */ O, O, O, O, O, VAbv, VBlw, O, B, B, B, O, O, O, O, O,
++ /* 0C60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0C70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Kannada */
++
++ /* 0C80 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
++ /* 0C90 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0CA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 0CB0 */ B, B, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
++ /* 0CC0 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
++ /* 0CD0 */ O, O, O, O, O, VPst, VPst, O, O, O, O, O, O, O, B, O,
++ /* 0CE0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0CF0 */ O, R, R, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Malayalam */
++
++ /* 0D00 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
++ /* 0D10 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, O, O, B, VPst, VPst,
++ /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O,
++ /* 0D50 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, IV,
++ /* 0D60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0D70 */ O, O, O, O, O, O, O, O, O, O, IND, IND, IND, IND, IND, IND,
++
++ /* Sinhala */
++
++ /* 0D80 */ O, O, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 0D90 */ IV, IV, IV, IV, IV, IV, IV, O, O, O, B, B, B, B, B, B,
++ /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O,
++ /* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst,
++ /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst,
++ /* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
++ /* 0DF0 */ O, O, VPst, VPst, O, O, O, O,
++
++#define use_offset_0x1000u 1352
++
++
++ /* Myanmar */
++
++ /* 1000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1020 */ B, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, VPst, VPst, VAbv, VAbv, VBlw,
++ /* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, H, VAbv, MPst, MPre, MBlw, MBlw, B,
++ /* 1040 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, GB, O,
++ /* 1050 */ B, B, IV, IV, IV, IV, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw,
++ /* 1060 */ MBlw, B, VPst, VMPst, VMPst, B, B, VPst, VPst, VMPst, VMPst, VMPst, VMPst, VMPst, B, B,
++ /* 1070 */ B, VAbv, VAbv, VAbv, VAbv, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst,
++ /* 1090 */ B, B, B, B, B, B, B, B, B, B, VMPst, VMPst, VPst, VAbv, O, O,
++
++#define use_offset_0x1700u 1512
++
++
++ /* Tagalog */
++
++ /* 1700 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, O, B, B,
++ /* 1710 */ B, B, VAbv, VBlw, VBlw, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Hanunoo */
++
++ /* 1720 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1730 */ B, B, VAbv, VBlw, VBlw, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Buhid */
++
++ /* 1740 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1750 */ B, B, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Tagbanwa */
++
++ /* 1760 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, O, B, B,
++ /* 1770 */ B, O, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Khmer */
++
++ /* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 17A0 */ B, B, B, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 17B0 */ IV, IV, IV, IV, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
++ /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM,
++ /* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O,
++ /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++#define use_offset_0x1900u 1752
++
++
++ /* Limbu */
++
++ /* 1900 */ GB, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O,
++ /* 1920 */ VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, O, O, O, O,
++ /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VAbv, FM, O, O, O, O,
++ /* 1940 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
++
++ /* Tai Le */
++
++ /* 1950 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1960 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, O,
++ /* 1970 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* New Tai Lue */
++
++ /* 1980 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 19A0 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
++ /* 19B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 19C0 */ B, B, B, B, B, B, B, B, VMPst, VMPst, O, O, O, O, O, O,
++ /* 19D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++ /* 19E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 19F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Buginese */
++
++ /* 1A00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1A10 */ B, B, B, B, B, B, B, VAbv, VBlw, VPre, VPst, VAbv, O, O, O, O,
++
++ /* Tai Tham */
++
++ /* 1A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1A30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, IV, IV, IV,
++ /* 1A50 */ IV, IV, IV, B, B, MPre, MBlw, FPst, FAbv, FAbv, FAbv, FBlw, FBlw, FBlw, FBlw, O,
++ /* 1A60 */ H, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre,
++ /* 1A70 */ VPre, VPre, VPre, VAbv, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, FM, FM, FM, O, O, FM,
++ /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++ /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++#define use_offset_0x1b00u 2168
++
++
++ /* Balinese */
++
++ /* 1B00 */ VMAbv, VMAbv, VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 1B10 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre,
++ /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O,
++ /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++ /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
++ /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Sundanese */
++
++ /* 1B80 */ VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
++ /* 1B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, H, SUB, SUB, B, B,
++ /* 1BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++
++ /* Batak */
++
++ /* 1BC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1BD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1BE0 */ B, B, B, B, IV, IV, CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv,
++ /* 1BF0 */ FAbv, FAbv, VPst, VPst, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Lepcha */
++
++ /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv,
++ /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FM, CMBlw, O, O, O, O, O, O, O, O,
++ /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B,
++
++#define use_offset_0x1cd0u 2504
++
++
++ /* Vedic Extensions */
++
++ /* 1CD0 */ VMAbv, VMAbv, VMAbv, O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw,
++ /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O,
++ /* 1CF0 */ O, O, VMPst, VMPst, VMAbv, O, O, O, VMAbv, VMAbv, O, O, O, O, O, O,
++
++#define use_offset_0x2008u 2552
++
++
++ /* General Punctuation */
++ O, O, O, O, ZWNJ, ZWJ, O, O,
++ /* 2010 */ GB, GB, GB, GB, GB, O, O, O,
++
++#define use_offset_0x2060u 2568
++
++ /* 2060 */ WJ, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Superscripts and Subscripts */
++
++ /* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O,
++ /* 2080 */ O, O, FM, FM, FM, O, O, O,
++
++#define use_offset_0xa800u 2608
++
++
++ /* Syloti Nagri */
++
++ /* A800 */ IV, IV, O, IV, IV, IV, VAbv, B, B, B, B, VMAbv, B, B, B, B,
++ /* A810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, O, O, O, O,
++ /* A830 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Phags-pa */
++
++ /* A840 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A850 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A860 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A870 */ B, B, B, B, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Saurashtra */
++
++ /* A880 */ VMPst, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* A890 */ IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A8A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A8B0 */ B, B, B, B, FPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst,
++ /* A8C0 */ VPst, VPst, VPst, VPst, H, O, O, O, O, O, O, O, O, O, O, O,
++ /* A8D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++ /* Devanagari Extended */
++
++ /* A8E0 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv,
++ /* A8F0 */ VMAbv, VMAbv, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Kayah Li */
++
++ /* A900 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A920 */ B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VAbv, VMBlw, VMBlw, VMBlw, O, O,
++
++ /* Rejang */
++
++ /* A930 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A940 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv,
++ /* A950 */ FAbv, FAbv, FPst, VPst, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* A960 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* A970 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Javanese */
++
++ /* A980 */ VMAbv, VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, B, B, B, IV, IV, IV, B,
++ /* A990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A9A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, SUB, MPst, MPst,
++ /* A9C0 */ H, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* A9D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++ /* Myanmar Extended-B */
++
++ /* A9E0 */ B, B, B, B, B, VAbv, O, B, B, B, B, B, B, B, B, B,
++ /* A9F0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O,
++
++ /* Cham */
++
++ /* AA00 */ IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B, B,
++ /* AA10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* AA20 */ B, B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre,
++ /* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MBlw, MBlw, O, O, O, O, O, O, O, O, O,
++ /* AA40 */ B, B, B, FAbv, B, B, B, B, B, B, B, B, FAbv, FPst, O, O,
++ /* AA50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++ /* Myanmar Extended-A */
++
++ /* AA60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* AA70 */ O, B, B, B, O, O, O, O, O, O, B, VMPst, VMAbv, VMPst, B, B,
++
++ /* Tai Viet */
++
++ /* AA80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* AA90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* AAA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* AAB0 */ VAbv, B, VAbv, VAbv, VBlw, B, B, VAbv, VAbv, B, B, B, B, B, VAbv, VMAbv,
++ /* AAC0 */ B, VMAbv, B, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* AAD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Meetei Mayek Extensions */
++
++ /* AAE0 */ IV, IV, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
++ /* AAF0 */ O, O, O, O, O, VMPst, H, O,
++
++#define use_offset_0xabc0u 3368
++
++
++ /* Meetei Mayek */
++
++ /* ABC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, IV, IV,
++ /* ABD0 */ B, IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O,
++ /* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++#define use_offset_0xfe00u 3432
++
++
++ /* Variation Selectors */
++
++ /* FE00 */ VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS,
++
++#define use_offset_0x10a00u 3448
++
++
++ /* Kharoshthi */
++
++ /* 10A00 */ B, VBlw, VBlw, VBlw, O, VAbv, VBlw, O, O, O, O, O, VBlw, VBlw, VMBlw, VMAbv,
++ /* 10A10 */ B, B, B, B, O, B, B, B, O, B, B, B, B, B, B, B,
++ /* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 10A30 */ B, B, B, B, O, O, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H,
++ /* 10A40 */ B, B, B, B, B, B, B, B,
++
++#define use_offset_0x11000u 3520
++
++
++ /* Brahmi */
++
++ /* 11000 */ VMPst, VMAbv, VMPst, R, R, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 11010 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,
++ /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O,
++ /* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
++ /* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B,
++ /* 11070 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Kaithi */
++
++ /* 11080 */ VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B,
++ /* 11090 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O,
++
++#define use_offset_0x11100u 3712
++
++
++ /* Chakma */
++
++ /* 11100 */ VMAbv, VMAbv, VMAbv, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B,
++ /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11120 */ B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv,
++ /* 11130 */ VAbv, VBlw, VBlw, H, VAbv, O, B, B, B, B, B, B, B, B, B, B,
++ /* 11140 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Mahajani */
++
++ /* 11150 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11160 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11170 */ B, B, B, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Sharada */
++
++ /* 11180 */ VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
++ /* 11190 */ IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,
++ /* 111C0 */ H, B, R, R, O, O, O, O, O, O, CMBlw, VAbv, VBlw, O, O, O,
++ /* 111D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++ /* Sinhala Archaic Numbers */
++
++ /* 111E0 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 111F0 */ B, B, B, B, B, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Khojki */
++
++ /* 11200 */ IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B,
++ /* 11210 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw,
++ /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv,
++
++#define use_offset_0x11280u 4024
++
++
++ /* Multani */
++
++ /* 11280 */ IV, IV, IV, IV, B, B, B, O, B, O, B, B, B, B, O, B,
++ /* 11290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, B,
++ /* 112A0 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
++
++ /* Khudawadi */
++
++ /* 112B0 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
++ /* 112C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 112D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv,
++ /* 112E0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, CMBlw, VBlw, O, O, O, O, O,
++ /* 112F0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++ /* Grantha */
++
++ /* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
++ /* 11310 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
++ /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPst,
++ /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
++ /* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O,
++ /* 11360 */ IV, IV, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
++ /* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
++
++#define use_offset_0x11480u 4272
++
++
++ /* Tirhuta */
++
++ /* 11480 */ O, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B,
++ /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv,
++ /* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O,
++ /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++
++#define use_offset_0x11580u 4368
++
++
++ /* Siddham */
++
++ /* 11580 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B,
++ /* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
++ /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H,
++ /* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 115D0 */ O, O, O, O, O, O, O, O, IV, IV, IV, IV, VBlw, VBlw, O, O,
++ /* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 115F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Modi */
++
++ /* 11600 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B,
++ /* 11610 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11620 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11630 */ VPst, VPst, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPst, VPst, VMAbv, VMPst, H,
++ /* 11640 */ VAbv, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 11650 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++ /* 11660 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 11670 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Takri */
++
++ /* 11680 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
++ /* 11690 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 116A0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMPst, VAbv, VPre, VPst,
++ /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, O, O, O, O, O, O, O, O,
++ /* 116C0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
++ /* 116D0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 116E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++ /* 116F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
++
++ /* Ahom */
++
++ /* 11700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
++ /* 11710 */ B, B, B, B, B, B, B, B, B, B, O, O, O, MBlw, MPre, MAbv,
++ /* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
++ /* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
++
++}; /* Table items: 4816; occupancy: 72% */
++
++USE_TABLE_ELEMENT_TYPE
++hb_use_get_categories (hb_codepoint_t u)
++{
++ switch (u >> 12)
++ {
++ case 0x0u:
++ if (hb_in_range (u, 0x0028u, 0x003Fu)) return use_table[u - 0x0028u + use_offset_0x0028u];
++ if (hb_in_range (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
++ if (hb_in_range (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
++ if (unlikely (u == 0x034Fu)) return CGJ;
++ break;
++
++ case 0x1u:
++ if (hb_in_range (u, 0x1000u, 0x109Fu)) return use_table[u - 0x1000u + use_offset_0x1000u];
++ if (hb_in_range (u, 0x1700u, 0x17EFu)) return use_table[u - 0x1700u + use_offset_0x1700u];
++ if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
++ if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
++ if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
++ break;
++
++ case 0x2u:
++ if (hb_in_range (u, 0x2008u, 0x2017u)) return use_table[u - 0x2008u + use_offset_0x2008u];
++ if (hb_in_range (u, 0x2060u, 0x2087u)) return use_table[u - 0x2060u + use_offset_0x2060u];
++ if (unlikely (u == 0x25CCu)) return GB;
++ break;
++
++ case 0xAu:
++ if (hb_in_range (u, 0xA800u, 0xAAF7u)) return use_table[u - 0xA800u + use_offset_0xa800u];
++ if (hb_in_range (u, 0xABC0u, 0xABFFu)) return use_table[u - 0xABC0u + use_offset_0xabc0u];
++ break;
++
++ case 0xFu:
++ if (hb_in_range (u, 0xFE00u, 0xFE0Fu)) return use_table[u - 0xFE00u + use_offset_0xfe00u];
++ break;
++
++ case 0x10u:
++ if (hb_in_range (u, 0x10A00u, 0x10A47u)) return use_table[u - 0x10A00u + use_offset_0x10a00u];
++ break;
++
++ case 0x11u:
++ if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
++ if (hb_in_range (u, 0x11100u, 0x11237u)) return use_table[u - 0x11100u + use_offset_0x11100u];
++ if (hb_in_range (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
++ if (hb_in_range (u, 0x11480u, 0x114DFu)) return use_table[u - 0x11480u + use_offset_0x11480u];
++ if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
++ if (unlikely (u == 0x1107Fu)) return HN;
++ break;
++
++ default:
++ break;
++ }
++ return USE_O;
++}
++
++#undef B
++#undef CGJ
++#undef FM
++#undef GB
++#undef H
++#undef HN
++#undef IND
++#undef IV
++#undef N
++#undef O
++#undef R
++#undef Rsv
++#undef S
++#undef SUB
++#undef VS
++#undef WJ
++#undef ZWJ
++#undef ZWNJ
++#undef CMBlw
++#undef CMAbv
++#undef FBlw
++#undef FPst
++#undef FAbv
++#undef MPre
++#undef MBlw
++#undef MPst
++#undef MAbv
++#undef SMBlw
++#undef SMAbv
++#undef VPre
++#undef VBlw
++#undef VPst
++#undef VAbv
++#undef VMPre
++#undef VMBlw
++#undef VMPst
++#undef VMAbv
++
++/* == End of generated table == */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-fallback.cc gfx/harfbuzz/src/hb-ot-shape-fallback.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-fallback.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-fallback.cc 2016-06-05 23:50:14.550729671 +0200
+@@ -224,7 +224,7 @@
+ pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+ break;
+ }
+- /* Fall through */
++ HB_FALLTHROUGH;
+
+ default:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+@@ -259,6 +259,7 @@
+ case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+ /* Add gap, fall-through. */
+ base_extents.height -= y_gap;
++ HB_FALLTHROUGH;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+@@ -279,6 +280,7 @@
+ /* Add gap, fall-through. */
+ base_extents.y_bearing += y_gap;
+ base_extents.height -= y_gap;
++ HB_FALLTHROUGH;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+@@ -418,13 +420,12 @@
+ _hb_buffer_assert_gsubgpos_vars (buffer);
+
+ unsigned int start = 0;
+- unsigned int last_cluster = buffer->info[0].cluster;
+ unsigned int count = buffer->len;
++ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 1; i < count; i++)
+- if (buffer->info[i].cluster != last_cluster) {
++ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) {
+ position_cluster (plan, font, buffer, start, i);
+ start = i;
+- last_cluster = buffer->info[i].cluster;
+ }
+ position_cluster (plan, font, buffer, start, count);
+ }
+@@ -441,13 +442,15 @@
+ OT::hb_apply_context_t c (1, font, buffer);
+ c.set_lookup_mask (plan->kern_mask);
+ c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
++ OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
++ skippy_iter.init (&c);
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ for (unsigned int idx = 0; idx < count;)
+ {
+- OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
++ skippy_iter.reset (idx, 1);
+ if (!skippy_iter.next ())
+ {
+ idx++;
+@@ -481,3 +484,70 @@
+ idx = skippy_iter.idx;
+ }
+ }
++
++
++/* Adjusts width of various spaces. */
++void
++_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer)
++{
++ if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
++ return;
++
++ hb_glyph_info_t *info = buffer->info;
++ hb_glyph_position_t *pos = buffer->pos;
++ unsigned int count = buffer->len;
++ for (unsigned int i = 0; i < count; i++)
++ if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
++ {
++ hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
++ hb_codepoint_t glyph;
++ typedef hb_unicode_funcs_t t;
++ switch (space_type)
++ {
++ case t::NOT_SPACE: /* Shouldn't happen. */
++ case t::SPACE:
++ break;
++
++ case t::SPACE_EM:
++ case t::SPACE_EM_2:
++ case t::SPACE_EM_3:
++ case t::SPACE_EM_4:
++ case t::SPACE_EM_5:
++ case t::SPACE_EM_6:
++ case t::SPACE_EM_16:
++ pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
++ break;
++
++ case t::SPACE_4_EM_18:
++ pos[i].x_advance = font->x_scale * 4 / 18;
++ break;
++
++ case t::SPACE_FIGURE:
++ for (char u = '0'; u <= '9'; u++)
++ if (font->get_glyph (u, 0, &glyph))
++ {
++ pos[i].x_advance = font->get_glyph_h_advance (glyph);
++ break;
++ }
++ break;
++
++ case t::SPACE_PUNCTUATION:
++ if (font->get_glyph ('.', 0, &glyph))
++ pos[i].x_advance = font->get_glyph_h_advance (glyph);
++ else if (font->get_glyph (',', 0, &glyph))
++ pos[i].x_advance = font->get_glyph_h_advance (glyph);
++ break;
++
++ case t::SPACE_NARROW:
++ /* Half-space?
++ * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
++ * However, in my testing, many fonts have their regular space being about that
++ * size. To me, a percentage of the space width makes more sense. Half is as
++ * good as any. */
++ pos[i].x_advance /= 2;
++ break;
++ }
++ }
++}
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-fallback-private.hh gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh
+--- gfx/harfbuzz/src_old/hb-ot-shape-fallback-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh 2016-06-05 23:50:13.114737132 +0200
+@@ -45,5 +45,9 @@
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
++HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
++ hb_font_t *font,
++ hb_buffer_t *buffer);
++
+
+ #endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape.h gfx/harfbuzz/src/hb-ot-shape.h
+--- gfx/harfbuzz/src_old/hb-ot-shape.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape.h 2016-06-05 23:50:20.781697361 +0200
+@@ -36,14 +36,14 @@
+ HB_BEGIN_DECLS
+
+ /* TODO port to shape-plan / set. */
+-void
++HB_EXTERN void
+ hb_ot_shape_glyphs_closure (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ hb_set_t *glyphs);
+
+-void
++HB_EXTERN void
+ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+ hb_tag_t table_tag,
+ hb_set_t *lookup_indexes /* OUT */);
+diff -uN gfx/harfbuzz/src_old/hb-ot-shape-normalize.cc gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+--- gfx/harfbuzz/src_old/hb-ot-shape-normalize.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-shape-normalize.cc 2016-06-05 23:50:16.988717013 +0200
+@@ -62,24 +62,12 @@
+ * with previous base, use that. This needs the itemizer to have this
+ * knowledge too. We need to provide assistance to the itemizer.
+ *
+- * - When a font does not support a character but supports its decomposition,
+- * well, use the decomposition (preferring the canonical decomposition, but
+- * falling back to the compatibility decomposition if necessary). The
+- * compatibility decomposition is really nice to have, for characters like
+- * ellipsis, or various-sized space characters.
++ * - When a font does not support a character but supports its canonical
++ * decomposition, well, use the decomposition.
+ *
+ * - The complex shapers can customize the compose and decompose functions to
+ * offload some of their requirements to the normalizer. For example, the
+ * Indic shaper may want to disallow recomposing of two matras.
+- *
+- * - We try compatibility decomposition if decomposing through canonical
+- * decomposition alone failed to find a sequence that the font supports.
+- * We don't try compatibility decomposition recursively during the canonical
+- * decomposition phase. This has minimal impact. There are only a handful
+- * of Greek letter that have canonical decompositions that include characters
+- * with compatibility decomposition. Those can be found using this command:
+- *
+- * egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
+ */
+
+ static bool
+@@ -88,7 +76,7 @@
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
+ {
+- return c->unicode->decompose (ab, a, b);
++ return (bool) c->unicode->decompose (ab, a, b);
+ }
+
+ static bool
+@@ -97,7 +85,7 @@
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+ {
+- return c->unicode->compose (a, b, ab);
++ return (bool) c->unicode->compose (a, b, ab);
+ }
+
+ static inline void
+@@ -110,8 +98,8 @@
+ output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
+ {
+ buffer->cur().glyph_index() = glyph;
+- buffer->output_glyph (unichar);
+- _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
++ buffer->output_glyph (unichar); /* This is very confusing indeed. */
++ _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
+ }
+
+ static inline void
+@@ -139,7 +127,7 @@
+ (b && !font->get_glyph (b, 0, &b_glyph)))
+ return 0;
+
+- bool has_a = font->get_glyph (a, 0, &a_glyph);
++ bool has_a = (bool) font->get_glyph (a, 0, &a_glyph);
+ if (shortest && has_a) {
+ /* Output a and b */
+ output_char (buffer, a, a_glyph);
+@@ -171,45 +159,57 @@
+ return 0;
+ }
+
+-/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+-static inline unsigned int
+-decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
+-{
+- unsigned int len, i;
+- hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+- hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+-
+- len = c->buffer->unicode->decompose_compatibility (u, decomposed);
+- if (!len)
+- return 0;
+-
+- for (i = 0; i < len; i++)
+- if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
+- return 0;
+-
+- for (i = 0; i < len; i++)
+- output_char (c->buffer, decomposed[i], glyphs[i]);
+-
+- return len;
+-}
+-
+ static inline void
+ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
+ {
+ hb_buffer_t * const buffer = c->buffer;
++ hb_codepoint_t u = buffer->cur().codepoint;
+ hb_codepoint_t glyph;
+
+- /* Kind of a cute waterfall here... */
+- if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
++ if (shortest && c->font->get_glyph (u, 0, &glyph))
++ {
+ next_char (buffer, glyph);
+- else if (decompose (c, shortest, buffer->cur().codepoint))
++ return;
++ }
++
++ if (decompose (c, shortest, u))
++ {
+ skip_char (buffer);
+- else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph))
++ return;
++ }
++
++ if (!shortest && c->font->get_glyph (u, 0, &glyph))
++ {
+ next_char (buffer, glyph);
+- else if (decompose_compatibility (c, buffer->cur().codepoint))
+- skip_char (buffer);
+- else
+- next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
++ return;
++ }
++
++ if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
++ {
++ hb_codepoint_t space_glyph;
++ hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
++ if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_glyph (0x0020u, 0, &space_glyph))
++ {
++ _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
++ next_char (buffer, space_glyph);
++ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
++ return;
++ }
++ }
++
++ if (u == 0x2011u)
++ {
++ /* U+2011 is the only sensible character that is a no-break version of another character
++ * and not a space. The space ones are handled already. Handle this lone one. */
++ hb_codepoint_t other_glyph;
++ if (c->font->get_glyph (0x2010u, 0, &other_glyph))
++ {
++ next_char (buffer, other_glyph);
++ return;
++ }
++ }
++
++ next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+ }
+
+ static inline void
+@@ -218,7 +218,7 @@
+ /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+ hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
+- for (; buffer->idx < end - 1;) {
++ for (; buffer->idx < end - 1 && !buffer->in_error;) {
+ if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
+ /* The next two lines are some ugly lines... But work. */
+ if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+@@ -254,13 +254,13 @@
+ decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+ {
+ hb_buffer_t * const buffer = c->buffer;
+- for (unsigned int i = buffer->idx; i < end; i++)
++ for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
+ if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
+ handle_variation_selector_cluster (c, end, short_circuit);
+ return;
+ }
+
+- while (buffer->idx < end)
++ while (buffer->idx < end && !buffer->in_error)
+ decompose_current_character (c, short_circuit);
+ }
+
+@@ -289,6 +289,8 @@
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+ {
++ if (unlikely (!buffer->len)) return;
++
+ _hb_buffer_assert_unicode_vars (buffer);
+
+ hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+@@ -318,11 +320,11 @@
+
+ buffer->clear_output ();
+ count = buffer->len;
+- for (buffer->idx = 0; buffer->idx < count;)
++ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
+ {
+ unsigned int end;
+ for (end = buffer->idx + 1; end < count; end++)
+- if (buffer->cur().cluster != buffer->info[end].cluster)
++ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+ break;
+
+ decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
+@@ -343,15 +345,13 @@
+ if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
+ break;
+
+- /* We are going to do a bubble-sort. Only do this if the
+- * sequence is short. Doing it on long sequences can result
+- * in an O(n^2) DoS. */
++ /* We are going to do a O(n^2). Only do this if the sequence is short. */
+ if (end - i > 10) {
+ i = end;
+ continue;
+ }
+
+- hb_bubble_sort (buffer->info + i, end - i, compare_combining_class);
++ buffer->sort (i, end, compare_combining_class);
+
+ i = end;
+ }
+@@ -370,7 +370,7 @@
+ count = buffer->len;
+ unsigned int starter = 0;
+ buffer->next_glyph ();
+- while (buffer->idx < count)
++ while (buffer->idx < count && !buffer->in_error)
+ {
+ hb_codepoint_t composed, glyph;
+ if (/* We don't try to compose a non-mark character with it's preceding starter.
+@@ -399,7 +399,7 @@
+ /* Modify starter and carry on. */
+ buffer->out_info[starter].codepoint = composed;
+ buffer->out_info[starter].glyph_index() = glyph;
+- _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
++ _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+
+ continue;
+ }
+diff -uN gfx/harfbuzz/src_old/hb-ot-tag.cc gfx/harfbuzz/src/hb-ot-tag.cc
+--- gfx/harfbuzz/src_old/hb-ot-tag.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-tag.cc 2016-06-05 23:50:22.342689280 +0200
+@@ -175,6 +175,11 @@
+ *
+ * Some items still missing. Those are commented out at the end.
+ * Keep sorted for bsearch.
++ *
++ * Updated as of 2015-05-06: OT1.7 on MS website has some newer
++ * items that we don't have here, eg. Zazaki. This is the new
++ * items in OpenType 1.7 (red items), most of which we have:
++ * http://www.microsoft.com/typography/otspec170/languagetags.htm
+ */
+
+ static const LangTag ot_languages[] = {
+@@ -217,9 +222,9 @@
+ {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */
+ {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */
+ {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
+- {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */
++ {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */
+ {"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */
+- {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */
++ {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */
+ {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
+ {"bft", HB_TAG('B','L','T',' ')}, /* Balti */
+ {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */
+@@ -346,11 +351,10 @@
+ {"gv", HB_TAG('M','N','X',' ')}, /* Manx */
+ {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
+ {"har", HB_TAG('H','R','I',' ')}, /* Harari */
+- {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */
+- {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
+- {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
++ {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */
++ {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
++ {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
+ {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
+- {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
+ {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
+ {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
+ {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
+@@ -542,6 +546,7 @@
+ {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */
+ {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */
+ {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */
++ {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */
+ {"ny", HB_TAG('C','H','I',' ')}, /* Chewa/Chichwa/Nyanja */
+ {"nym", HB_TAG('N','Y','M',' ')}, /* Nyamwezi */
+ {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */
+@@ -595,8 +600,8 @@
+ {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
+ {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
+ {"sat", HB_TAG('S','A','T',' ')}, /* Santali */
+- {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
+ {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
++ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
+ {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
+ {"sco", HB_TAG('S','C','O',' ')}, /* Scots */
+ {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */
+@@ -684,8 +689,8 @@
+ {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */
+ {"ve", HB_TAG('V','E','N',' ')}, /* Venda */
+ {"vec", HB_TAG('V','E','C',' ')}, /* Venetian */
+- {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
+ {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
++ {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
+ {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
+ {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
+ {"vro", HB_TAG('V','R','O',' ')}, /* Võro */
+@@ -694,9 +699,9 @@
+ {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
+ {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
+ {"wle", HB_TAG('S','I','G',' ')}, /* Wolane */
++ {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
+ {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
+ {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
+- {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
+ {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
+ {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
+ {"xog", HB_TAG('X','O','G',' ')}, /* Soga */
+@@ -727,7 +732,6 @@
+ /*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */
+ /*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
+ /*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */
+-/*{"fonipa", HB_TAG('I','P','P','H')},*/ /* Phonetic transcription—IPA conventions */
+ /*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
+ /*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */
+ /*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */
+@@ -826,6 +830,14 @@
+ }
+ }
+
++ /*
++ * The International Phonetic Alphabet is a variant tag in BCP-47,
++ * which can be applied to any language.
++ */
++ if (strstr (lang_str, "-fonipa")) {
++ return HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */
++ }
++
+ /* Find a language matching in the first component */
+ {
+ const LangTag *lang_tag;
+@@ -864,6 +876,15 @@
+ return HB_OT_TAG_DEFAULT_LANGUAGE;
+ }
+
++/**
++ * hb_ot_tag_to_language:
++ *
++ *
++ *
++ * Return value: (transfer none):
++ *
++ * Since: 0.9.2
++ **/
+ hb_language_t
+ hb_ot_tag_to_language (hb_tag_t tag)
+ {
+@@ -886,6 +907,12 @@
+ }
+ }
+
++ /* struct LangTag has only room for 3-letter language tags. */
++ switch (tag) {
++ case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
++ return hb_language_from_string ("und-fonipa", -1);
++ }
++
+ /* Else return a custom language in the form of "x-hbotABCD" */
+ {
+ unsigned char buf[11] = "x-hbot";
+@@ -900,4 +927,27 @@
+ }
+ }
+
++static inline void
++test_langs_sorted (void)
++{
++ for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
++ {
++ int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
++ if (c >= 0)
++ {
++ fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
++ i, ot_languages[i-1].language, c, ot_languages[i].language);
++ abort();
++ }
++ }
++}
++
++#ifdef MAIN
++int
++main (void)
++{
++ test_langs_sorted ();
++ return 0;
++}
+
++#endif
+diff -uN gfx/harfbuzz/src_old/hb-ot-tag.h gfx/harfbuzz/src/hb-ot-tag.h
+--- gfx/harfbuzz/src_old/hb-ot-tag.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ot-tag.h 2016-06-05 23:50:23.562682979 +0200
+@@ -39,18 +39,18 @@
+ #define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
+ #define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
+
+-void
++HB_EXTERN void
+ hb_ot_tags_from_script (hb_script_t script,
+ hb_tag_t *script_tag_1,
+ hb_tag_t *script_tag_2);
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_ot_tag_to_script (hb_tag_t tag);
+
+-hb_tag_t
++HB_EXTERN hb_tag_t
+ hb_ot_tag_from_language (hb_language_t language);
+
+-hb_language_t
++HB_EXTERN hb_language_t
+ hb_ot_tag_to_language (hb_tag_t tag);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-private.hh gfx/harfbuzz/src/hb-private.hh
+--- gfx/harfbuzz/src_old/hb-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-private.hh 2016-06-05 23:50:26.191669403 +0200
+@@ -54,6 +54,23 @@
+ #include <stdarg.h>
+
+
++/* Compile-time custom allocator support. */
++
++#if defined(hb_malloc_impl) \
++ && defined(hb_calloc_impl) \
++ && defined(hb_realloc_impl) \
++ && defined(hb_free_impl)
++extern "C" void* hb_malloc_impl(size_t size);
++extern "C" void* hb_calloc_impl(size_t nmemb, size_t size);
++extern "C" void* hb_realloc_impl(void *ptr, size_t size);
++extern "C" void hb_free_impl(void *ptr);
++#define malloc hb_malloc_impl
++#define calloc hb_calloc_impl
++#define realloc hb_realloc_impl
++#define free hb_free_impl
++#endif
++
++
+ /* Compiler attributes */
+
+
+@@ -94,22 +111,6 @@
+ # endif
+ #endif
+
+-#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
+-#define snprintf _snprintf
+-/* Windows CE only has _strdup, while rest of Windows has both. */
+-#define strdup _strdup
+-#endif
+-
+-#ifdef _MSC_VER
+-#undef inline
+-#define inline __inline
+-#endif
+-
+-#ifdef __STRICT_ANSI__
+-#undef inline
+-#define inline __inline__
+-#endif
+-
+ #if __GNUC__ >= 3
+ #define HB_FUNC __PRETTY_FUNCTION__
+ #elif defined(_MSC_VER)
+@@ -118,6 +119,36 @@
+ #define HB_FUNC __func__
+ #endif
+
++/*
++ * Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
++ * HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
++ * cases that fall through without a break or return statement. HB_FALLTHROUGH
++ * is only needed on cases that have code:
++ *
++ * switch (foo) {
++ * case 1: // These cases have no code. No fallthrough annotations are needed.
++ * case 2:
++ * case 3:
++ * foo = 4; // This case has code, so a fallthrough annotation is needed:
++ * HB_FALLTHROUGH;
++ * default:
++ * return foo;
++ * }
++ */
++#if defined(__clang__) && __cplusplus >= 201103L
++ /* clang's fallthrough annotations are only available starting in C++11. */
++# define HB_FALLTHROUGH [[clang::fallthrough]]
++#elif defined(_MSC_VER)
++ /*
++ * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):
++ * https://msdn.microsoft.com/en-us/library/ms235402%28VS.80%29.aspx
++ */
++# include <sal.h>
++# define HB_FALLTHROUGH __fallthrough
++#else
++# define HB_FALLTHROUGH /* FALLTHROUGH */
++#endif
++
+ #if defined(_WIN32) || defined(__CYGWIN__)
+ /* We need Windows Vista for both Uniscribe backend and for
+ * MemoryBarrier. We don't support compiling on Windows XP,
+@@ -134,14 +165,24 @@
+ # ifndef STRICT
+ # define STRICT 1
+ # endif
+-#endif
+
+-#ifdef _WIN32_WCE
+-/* Some things not defined on Windows CE. */
+-#define MemoryBarrier()
+-#define getenv(Name) NULL
+-#define setlocale(Category, Locale) "C"
++# if defined(_WIN32_WCE)
++ /* Some things not defined on Windows CE. */
++# define strdup _strdup
++# define getenv(Name) NULL
++# if _WIN32_WCE < 0x800
++# define setlocale(Category, Locale) "C"
+ static int errno = 0; /* Use something better? */
++# endif
++# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
++# define getenv(Name) NULL
++# endif
++# if defined(_MSC_VER) && _MSC_VER < 1900
++# define snprintf _snprintf
++# elif defined(_MSC_VER) && _MSC_VER >= 1900
++# /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
++# define strdup _strdup
++# endif
+ #endif
+
+ #if HAVE_ATEXIT
+@@ -202,8 +243,9 @@
+ #define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
+ #define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
+
+-#define ASSERT_STATIC_EXPR(_cond)((void) sizeof (char[(_cond) ? 1 : -1]))
+-#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1]))
++template <unsigned int cond> class hb_assert_constant_t {};
++
++#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
+
+ #define _PASTE1(a,b) a##b
+ #define PASTE(a,b) _PASTE1(a,b)
+@@ -256,8 +298,8 @@
+
+ /* Void! */
+ struct _hb_void_t {};
+-typedef const _hb_void_t &hb_void_t;
+-#define HB_VOID (* (const _hb_void_t *) NULL)
++typedef const _hb_void_t *hb_void_t;
++#define HB_VOID ((const _hb_void_t *) NULL)
+
+ /* Return the number of 1 bits in mask. */
+ static inline HB_CONST_FUNC unsigned int
+@@ -583,6 +625,30 @@
+ #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+ #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+
++static inline void
++_hb_print_func (const char *func)
++{
++ if (func)
++ {
++ unsigned int func_len = strlen (func);
++ /* Skip "static" */
++ if (0 == strncmp (func, "static ", 7))
++ func += 7;
++ /* Skip "typename" */
++ if (0 == strncmp (func, "typename ", 9))
++ func += 9;
++ /* Skip return type */
++ const char *space = strchr (func, ' ');
++ if (space)
++ func = space + 1;
++ /* Skip parameter list */
++ const char *paren = strchr (func, '(');
++ if (paren)
++ func_len = paren - func;
++ fprintf (stderr, "%.*s", func_len, func);
++ }
++}
++
+ template <int max_level> static inline void
+ _hb_debug_msg_va (const char *what,
+ const void *obj,
+@@ -628,27 +694,13 @@
+ } else
+ fprintf (stderr, " " VRBAR LBAR);
+
+- if (func)
+- {
+- unsigned int func_len = strlen (func);
+-#ifndef HB_DEBUG_VERBOSE
+- /* Skip "typename" */
+- if (0 == strncmp (func, "typename ", 9))
+- func += 9;
+- /* Skip return type */
+- const char *space = strchr (func, ' ');
+- if (space)
+- func = space + 1;
+- /* Skip parameter list */
+- const char *paren = strchr (func, '(');
+- if (paren)
+- func_len = paren - func;
+-#endif
+- fprintf (stderr, "%.*s: ", func_len, func);
+- }
++ _hb_print_func (func);
+
+ if (message)
++ {
++ fprintf (stderr, ": ");
+ vfprintf (stderr, message, ap);
++ }
+
+ fprintf (stderr, "\n");
+ }
+@@ -738,7 +790,7 @@
+ static inline void _hb_warn_no_return (bool returned)
+ {
+ if (unlikely (!returned)) {
+- fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report.\n");
++ fprintf (stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n");
+ }
+ }
+ template <>
+@@ -773,7 +825,7 @@
+ inline ret_t ret (ret_t v, unsigned int line = 0)
+ {
+ if (unlikely (returned)) {
+- fprintf (stderr, "OUCH, double calls to TRACE_RETURN. This is a bug, please report.\n");
++ fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
+ return v;
+ }
+
+@@ -804,7 +856,7 @@
+ inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
+ };
+
+-#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
++#define return_trace(RET) return trace.ret (RET, __LINE__)
+
+ /* Misc */
+
+@@ -820,7 +872,7 @@
+ /* The sizeof() is here to force template instantiation.
+ * I'm sure there are better ways to do this but can't think of
+ * one right now. Declaring a variable won't work as HB_UNUSED
+- * is unsable on some platforms and unused types are less likely
++ * is unusable on some platforms and unused types are less likely
+ * to generate a warning than unused variables. */
+ ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+
+@@ -842,51 +894,68 @@
+ }
+
+
++/* Enable bitwise ops on enums marked as flags_t */
++/* To my surprise, looks like the function resolver is happy to silently cast
++ * one enum to another... So this doesn't provide the type-checking that I
++ * originally had in mind... :(.
++ *
++ * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
++ */
++#ifdef _MSC_VER
++# pragma warning(disable:4200)
++# pragma warning(disable:4800)
++#endif
++#define HB_MARK_AS_FLAG_T(T) \
++ extern "C++" { \
++ static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
++ static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
++ static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
++ static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
++ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
++ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
++ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
++ }
++
++
+ /* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+- * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
++ * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+-#define FLAG(x) (1<<(x))
++#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
++#define FLAG_SAFE(x) (1U << (x))
++#define FLAG_UNSAFE(x) ((x) < 32 ? FLAG_SAFE(x) : 0)
+ #define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
+
+
+ template <typename T, typename T2> static inline void
+-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
++hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
+ {
+- if (unlikely (!len))
+- return;
+-
+- unsigned int k = len - 1;
+- do {
+- unsigned int new_k = 0;
+-
+- for (unsigned int j = 0; j < k; j++)
+- if (compar (&array[j], &array[j+1]) > 0)
+- {
+- {
+- T t;
+- t = array[j];
+- array[j] = array[j + 1];
+- array[j + 1] = t;
+- }
+- if (array2)
+- {
+- T2 t;
+- t = array2[j];
+- array2[j] = array2[j + 1];
+- array2[j + 1] = t;
+- }
+-
+- new_k = j;
+- }
+- k = new_k;
+- } while (k);
++ for (unsigned int i = 1; i < len; i++)
++ {
++ unsigned int j = i;
++ while (j && compar (&array[j - 1], &array[i]) > 0)
++ j--;
++ if (i == j)
++ continue;
++ /* Move item i to occupy place for item j, shift what's in between. */
++ {
++ T t = array[i];
++ memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
++ array[j] = t;
++ }
++ if (array2)
++ {
++ T2 t = array2[i];
++ memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
++ array2[j] = t;
++ }
++ }
+ }
+
+ template <typename T> static inline void
+-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
++hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+ {
+- hb_bubble_sort (array, len, compar, (int *) NULL);
++ hb_stable_sort (array, len, compar, (int *) NULL);
+ }
+
+ static inline hb_bool_t
+@@ -936,5 +1005,7 @@
+ return _hb_options.opts;
+ }
+
++/* Size signifying variable-sized array */
++#define VAR 1
+
+ #endif /* HB_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-set.cc gfx/harfbuzz/src/hb-set.cc
+--- gfx/harfbuzz/src_old/hb-set.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-set.cc 2016-06-05 23:50:28.650656740 +0200
+@@ -35,7 +35,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_set_t *
+ hb_set_create (void)
+@@ -55,7 +55,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_set_t *
+ hb_set_get_empty (void)
+@@ -76,7 +76,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_set_t *
+ hb_set_reference (hb_set_t *set)
+@@ -88,7 +88,7 @@
+ * hb_set_destroy: (skip)
+ * @set: a set.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_destroy (hb_set_t *set)
+@@ -110,7 +110,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_set_set_user_data (hb_set_t *set,
+@@ -129,7 +129,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_set_get_user_data (hb_set_t *set,
+@@ -147,7 +147,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_set_allocation_successful (const hb_set_t *set HB_UNUSED)
+@@ -161,7 +161,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_clear (hb_set_t *set)
+@@ -177,7 +177,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_set_is_empty (const hb_set_t *set)
+@@ -194,7 +194,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_set_has (const hb_set_t *set,
+@@ -210,7 +210,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_add (hb_set_t *set,
+@@ -227,7 +227,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_set_add_range (hb_set_t *set,
+@@ -244,7 +244,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_del (hb_set_t *set,
+@@ -261,7 +261,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_set_del_range (hb_set_t *set,
+@@ -280,7 +280,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_set_is_equal (const hb_set_t *set,
+@@ -296,7 +296,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_set (hb_set_t *set,
+@@ -312,7 +312,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_union (hb_set_t *set,
+@@ -328,7 +328,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_intersect (hb_set_t *set,
+@@ -344,7 +344,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_subtract (hb_set_t *set,
+@@ -360,7 +360,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_set_symmetric_difference (hb_set_t *set,
+@@ -375,7 +375,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.10
+ **/
+ void
+ hb_set_invert (hb_set_t *set)
+@@ -391,7 +391,7 @@
+ *
+ * Return value: set population.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ unsigned int
+ hb_set_get_population (const hb_set_t *set)
+@@ -407,7 +407,7 @@
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_codepoint_t
+ hb_set_get_min (const hb_set_t *set)
+@@ -423,7 +423,7 @@
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_codepoint_t
+ hb_set_get_max (const hb_set_t *set)
+@@ -440,7 +440,7 @@
+ *
+ * Return value: whether there was a next value.
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_set_next (const hb_set_t *set,
+@@ -460,7 +460,7 @@
+ *
+ * Return value: whether there was a next range.
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_set_next_range (const hb_set_t *set,
+diff -uN gfx/harfbuzz/src_old/hb-set.h gfx/harfbuzz/src/hb-set.h
+--- gfx/harfbuzz/src_old/hb-set.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-set.h 2016-06-05 23:50:29.745651091 +0200
+@@ -36,114 +36,117 @@
+ HB_BEGIN_DECLS
+
+
++/*
++ * Since: 0.9.21
++ */
+ #define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
+ typedef struct hb_set_t hb_set_t;
+
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_create (void);
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_get_empty (void);
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_reference (hb_set_t *set);
+
+-void
++HB_EXTERN void
+ hb_set_destroy (hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_set_user_data (hb_set_t *set,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+-void *
++HB_EXTERN void *
+ hb_set_get_user_data (hb_set_t *set,
+ hb_user_data_key_t *key);
+
+
+ /* Returns false if allocation has failed before */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_allocation_successful (const hb_set_t *set);
+
+-void
++HB_EXTERN void
+ hb_set_clear (hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_is_empty (const hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_has (const hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+ /* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1
+ * which we will use as a sentinel. */
+-void
++HB_EXTERN void
+ hb_set_add (hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+-void
++HB_EXTERN void
+ hb_set_add_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
+-void
++HB_EXTERN void
+ hb_set_del (hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+-void
++HB_EXTERN void
+ hb_set_del_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_is_equal (const hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_set (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_union (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_intersect (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_subtract (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_symmetric_difference (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_invert (hb_set_t *set);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_set_get_population (const hb_set_t *set);
+
+ /* Returns -1 if set empty. */
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_set_get_min (const hb_set_t *set);
+
+ /* Returns -1 if set empty. */
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_set_get_max (const hb_set_t *set);
+
+ /* Pass -1 in to get started. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_next (const hb_set_t *set,
+ hb_codepoint_t *codepoint);
+
+ /* Pass -1 for first and last to get started. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_next_range (const hb_set_t *set,
+ hb_codepoint_t *first,
+ hb_codepoint_t *last);
+diff -uN gfx/harfbuzz/src_old/hb-set-private.hh gfx/harfbuzz/src/hb-set-private.hh
+--- gfx/harfbuzz/src_old/hb-set-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-set-private.hh 2016-06-05 23:50:27.437662982 +0200
+@@ -36,7 +36,15 @@
+ * "approximate member query". Conceptually these are like Bloom
+ * Filter and Quotient Filter, however, much smaller, faster, and
+ * designed to fit the requirements of our uses for glyph coverage
+- * queries. As a result, our filters have much higher.
++ * queries.
++ *
++ * Our filters are highly accurate if the lookup covers fairly local
++ * set of glyphs, but fully flooded and ineffective if coverage is
++ * all over the place.
++ *
++ * The frozen-set can be used instead of a digest, to trade more
++ * memory for 100% accuracy, but in practice, that doesn't look like
++ * an attractive trade-off.
+ */
+
+ template <typename mask_t, unsigned int shift>
+@@ -145,6 +153,8 @@
+
+ struct hb_set_t
+ {
++ friend struct hb_frozen_set_t;
++
+ hb_object_header_t header;
+ ASSERT_POD ();
+ bool in_error;
+@@ -326,7 +336,7 @@
+ static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+ elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
+- elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
++ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+ elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+ elt_t elts[ELTS]; /* XXX 8kb */
+@@ -335,6 +345,58 @@
+ ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
+ };
+
++struct hb_frozen_set_t
++{
++ static const unsigned int SHIFT = hb_set_t::SHIFT;
++ static const unsigned int BITS = hb_set_t::BITS;
++ static const unsigned int MASK = hb_set_t::MASK;
++ typedef hb_set_t::elt_t elt_t;
++
++ inline void init (const hb_set_t &set)
++ {
++ start = count = 0;
++ elts = NULL;
++
++ unsigned int max = set.get_max ();
++ if (max == set.INVALID)
++ return;
++ unsigned int min = set.get_min ();
++ const elt_t &min_elt = set.elt (min);
++
++ start = min & ~MASK;
++ count = max - start + 1;
++ unsigned int num_elts = (count + BITS - 1) / BITS;
++ unsigned int elts_size = num_elts * sizeof (elt_t);
++ elts = (elt_t *) malloc (elts_size);
++ if (unlikely (!elts))
++ {
++ start = count = 0;
++ return;
++ }
++ memcpy (elts, &min_elt, elts_size);
++ }
++
++ inline void fini (void)
++ {
++ if (elts)
++ free (elts);
++ }
++
++ inline bool has (hb_codepoint_t g) const
++ {
++ /* hb_codepoint_t is unsigned. */
++ g -= start;
++ if (unlikely (g > count)) return false;
++ return !!(elt (g) & mask (g));
++ }
++
++ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
++ elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
++
++ private:
++ hb_codepoint_t start, count;
++ elt_t *elts;
++};
+
+
+ #endif /* HB_SET_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-shape.cc gfx/harfbuzz/src/hb-shape.cc
+--- gfx/harfbuzz/src_old/hb-shape.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-shape.cc 2016-06-05 23:50:35.179623187 +0200
+@@ -33,6 +33,17 @@
+ #include "hb-buffer-private.hh"
+ #include "hb-font-private.hh"
+
++/**
++ * SECTION:hb-shape
++ * @title: Shaping
++ * @short_description: Conversion of text strings into positioned glyphs
++ * @include: hb.h
++ *
++ * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
++ * which are sequences of Unicode characters that use the same font and have
++ * the same text direction, script and language. After shaping the buffer
++ * contains the output glyphs and their positions.
++ **/
+
+ static bool
+ parse_space (const char **pp, const char *end)
+@@ -198,15 +209,18 @@
+
+ /**
+ * hb_feature_from_string:
+- * @str: (array length=len):
+- * @len:
+- * @feature: (out) (allow-none):
++ * @str: (array length=len) (element-type uint8_t): a string to parse
++ * @len: length of @str, or -1 if string is %NULL terminated
++ * @feature: (out): the #hb_feature_t to initialize with the parsed values
++ *
++ * Parses a string into a #hb_feature_t.
+ *
+- *
++ * TODO: document the syntax here.
+ *
+- * Return value:
++ * Return value:
++ * %true if @str is successfully parsed, %false otherwise.
+ *
+- * Since: 1.0
++ * Since: 0.9.5
+ **/
+ hb_bool_t
+ hb_feature_from_string (const char *str, int len,
+@@ -231,13 +245,15 @@
+
+ /**
+ * hb_feature_to_string:
+- * @feature:
+- * @buf: (array length=size):
+- * @size:
++ * @feature: an #hb_feature_t to convert
++ * @buf: (array length=size) (out): output string
++ * @size: the allocated size of @buf
++ *
++ * Converts a #hb_feature_t into a %NULL-terminated string in the format
++ * understood by hb_feature_from_string(). The client in responsible for
++ * allocating big enough size for @buf, 128 bytes is more than enough.
+ *
+- *
+- *
+- * Since: 1.0
++ * Since: 0.9.5
+ **/
+ void
+ hb_feature_to_string (hb_feature_t *feature,
+@@ -279,20 +295,23 @@
+
+ static const char **static_shaper_list;
+
+-static inline
++#ifdef HB_USE_ATEXIT
++static
+ void free_static_shaper_list (void)
+ {
+ free (static_shaper_list);
+ }
++#endif
+
+ /**
+ * hb_shape_list_shapers:
+ *
+- *
++ * Retrieves the list of shapers supported by HarfBuzz.
+ *
+- * Return value: (transfer none):
++ * Return value: (transfer none) (array zero-terminated=1): an array of
++ * constant strings
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ const char **
+ hb_shape_list_shapers (void)
+@@ -331,17 +350,21 @@
+
+ /**
+ * hb_shape_full:
+- * @font: a font.
+- * @buffer: a buffer.
+- * @features: (array length=num_features):
+- * @num_features:
+- * @shaper_list: (array zero-terminated=1):
+- *
+- *
++ * @font: an #hb_font_t to use for shaping
++ * @buffer: an #hb_buffer_t to shape
++ * @features: (array length=num_features) (allow-none): an array of user
++ * specified #hb_feature_t or %NULL
++ * @num_features: the length of @features array
++ * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated
++ * array of shapers to use or %NULL
++ *
++ * See hb_shape() for details. If @shaper_list is not %NULL, the specified
++ * shapers will be used in the given order, otherwise the default shapers list
++ * will be used.
+ *
+- * Return value:
++ * Return value: %FALSE if all shapers failed, %TRUE otherwise
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_shape_full (hb_font_t *font,
+@@ -350,11 +373,6 @@
+ unsigned int num_features,
+ const char * const *shaper_list)
+ {
+- if (unlikely (!buffer->len))
+- return true;
+-
+- assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+-
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+ hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+ hb_shape_plan_destroy (shape_plan);
+@@ -366,14 +384,19 @@
+
+ /**
+ * hb_shape:
+- * @font: a font.
+- * @buffer: a buffer.
+- * @features: (array length=num_features):
+- * @num_features:
++ * @font: an #hb_font_t to use for shaping
++ * @buffer: an #hb_buffer_t to shape
++ * @features: (array length=num_features) (allow-none): an array of user
++ * specified #hb_feature_t or %NULL
++ * @num_features: the length of @features array
++ *
++ * Shapes @buffer using @font turning its Unicode characters content to
++ * positioned glyphs. If @features is not %NULL, it will be used to control the
++ * features applied during shaping.
+ *
+- *
++ * Return value: %FALSE if all shapers failed, %TRUE otherwise
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_shape (hb_font_t *font,
+diff -uN gfx/harfbuzz/src_old/hb-shape.h gfx/harfbuzz/src/hb-shape.h
+--- gfx/harfbuzz/src_old/hb-shape.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-shape.h 2016-06-05 23:50:36.664615573 +0200
+@@ -47,32 +47,29 @@
+ unsigned int end;
+ } hb_feature_t;
+
+-/* len=-1 means str is NUL-terminated */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature);
+
+-/* Something like 128 bytes is more than enough.
+- * nul-terminates. */
+-void
++HB_EXTERN void
+ hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size);
+
+
+-void
++HB_EXTERN void
+ hb_shape (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_full (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shaper_list);
+
+-const char **
++HB_EXTERN const char **
+ hb_shape_list_shapers (void);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-shape-plan.cc gfx/harfbuzz/src/hb-shape-plan.cc
+--- gfx/harfbuzz/src_old/hb-shape-plan.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-shape-plan.cc 2016-06-05 23:50:32.402637444 +0200
+@@ -106,7 +106,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_shape_plan_t *
+ hb_shape_plan_create (hb_face_t *face,
+@@ -126,9 +126,9 @@
+
+ if (unlikely (!face))
+ face = hb_face_get_empty ();
+- if (unlikely (!props || hb_object_is_inert (face)))
++ if (unlikely (!props))
+ return hb_shape_plan_get_empty ();
+- if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
++ if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
+ return hb_shape_plan_get_empty ();
+ if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+ free (features);
+@@ -158,7 +158,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_shape_plan_t *
+ hb_shape_plan_get_empty (void)
+@@ -194,7 +194,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_shape_plan_t *
+ hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
+@@ -208,7 +208,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void
+ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
+@@ -236,7 +236,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
+@@ -257,7 +257,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ void *
+ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
+@@ -279,7 +279,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_bool_t
+ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
+@@ -293,9 +293,13 @@
+ num_features,
+ shape_plan->shaper_func);
+
+- if (unlikely (hb_object_is_inert (shape_plan) ||
+- hb_object_is_inert (font) ||
+- hb_object_is_inert (buffer)))
++ if (unlikely (!buffer->len))
++ return true;
++
++ assert (!hb_object_is_inert (buffer));
++ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
++
++ if (unlikely (hb_object_is_inert (shape_plan)))
+ return false;
+
+ assert (shape_plan->face_unsafe == font->face);
+@@ -396,7 +400,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ hb_shape_plan_t *
+ hb_shape_plan_create_cached (hb_face_t *face,
+@@ -453,6 +457,10 @@
+
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
++ /* Don't add to the cache if face is inert. */
++ if (unlikely (hb_object_is_inert (face)))
++ return shape_plan;
++
+ /* Don't add the plan to the cache if there were user features with non-global ranges */
+
+ if (hb_non_global_user_features_present (user_features, num_user_features))
+@@ -483,7 +491,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.7
+ **/
+ const char *
+ hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
+diff -uN gfx/harfbuzz/src_old/hb-shape-plan.h gfx/harfbuzz/src/hb-shape-plan.h
+--- gfx/harfbuzz/src_old/hb-shape-plan.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-shape-plan.h 2016-06-05 23:50:33.950629490 +0200
+@@ -38,49 +38,49 @@
+
+ typedef struct hb_shape_plan_t hb_shape_plan_t;
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_create (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_create_cached (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_get_empty (void);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+-void
++HB_EXTERN void
+ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+-void *
++HB_EXTERN void *
+ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key);
+
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+-const char *
++HB_EXTERN const char *
+ hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-shaper.cc gfx/harfbuzz/src/hb-shaper.cc
+--- gfx/harfbuzz/src_old/hb-shaper.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-shaper.cc 2016-06-05 23:50:41.554590551 +0200
+@@ -40,12 +40,14 @@
+
+ static const hb_shaper_pair_t *static_shapers;
+
+-static inline
++#ifdef HB_USE_ATEXIT
++static
+ void free_static_shapers (void)
+ {
+ if (unlikely (static_shapers != all_shapers))
+ free ((void *) static_shapers);
+ }
++#endif
+
+ const hb_shaper_pair_t *
+ _hb_shapers_get (void)
+@@ -62,7 +64,7 @@
+ }
+
+ /* Not found; allocate one. */
+- shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
++ shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
+ if (unlikely (!shapers)) {
+ (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+ return (const hb_shaper_pair_t *) all_shapers;
+diff -uN gfx/harfbuzz/src_old/hb-shaper-list.hh gfx/harfbuzz/src/hb-shaper-list.hh
+--- gfx/harfbuzz/src_old/hb-shaper-list.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-shaper-list.hh 2016-06-05 23:50:39.106603073 +0200
+@@ -46,6 +46,9 @@
+ #ifdef HAVE_UNISCRIBE
+ HB_SHAPER_IMPLEMENT (uniscribe)
+ #endif
++#ifdef HAVE_DIRECTWRITE
++HB_SHAPER_IMPLEMENT (directwrite)
++#endif
+ #ifdef HAVE_CORETEXT
+ HB_SHAPER_IMPLEMENT (coretext)
+ #endif
+diff -uN gfx/harfbuzz/src_old/hb-shaper-private.hh gfx/harfbuzz/src/hb-shaper-private.hh
+--- gfx/harfbuzz/src_old/hb-shaper-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-shaper-private.hh 2016-06-05 23:50:40.352596696 +0200
+@@ -79,10 +79,9 @@
+ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+
+ #define HB_SHAPER_DATA_DESTROY(shaper, object) \
+- if (object->shaper_data.shaper && \
+- object->shaper_data.shaper != HB_SHAPER_DATA_INVALID && \
+- object->shaper_data.shaper != HB_SHAPER_DATA_SUCCEEDED) \
+- HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA (shaper, object));
++ if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
++ if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
++ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
+
+ #define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+ static inline bool \
+diff -uN gfx/harfbuzz/src_old/hb-ucdn.cc gfx/harfbuzz/src/hb-ucdn.cc
+--- gfx/harfbuzz/src_old/hb-ucdn.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-ucdn.cc 2016-06-05 23:50:42.748584458 +0200
+@@ -148,6 +148,12 @@
+ HB_SCRIPT_SIDDHAM,
+ HB_SCRIPT_TIRHUTA,
+ HB_SCRIPT_WARANG_CITI,
++ HB_SCRIPT_AHOM,
++ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS,
++ HB_SCRIPT_HATRAN,
++ HB_SCRIPT_MULTANI,
++ HB_SCRIPT_OLD_HUNGARIAN,
++ HB_SCRIPT_SIGNWRITING,
+ };
+
+ static hb_unicode_combining_class_t
+diff -uN gfx/harfbuzz/src_old/hb-unicode.cc gfx/harfbuzz/src/hb-unicode.cc
+--- gfx/harfbuzz/src_old/hb-unicode.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-unicode.cc 2016-06-05 23:50:45.673569556 +0200
+@@ -146,24 +146,19 @@
+ }
+
+ #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
+-#ifdef _MSC_VER
+-#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
+-#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
+-#else
+-#warning "Could not find any Unicode functions implementation, you have to provide your own"
+-#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
+-#endif
++#error "Could not find any Unicode functions implementation, you have to provide your own"
++#error "Consider building hb-ucdn.c. If you absolutely want to build without any, check the code."
+ #endif
+
+ /**
+ * hb_unicode_funcs_create: (Xconstructor)
+- * @parent: (allow-none):
++ * @parent: (nullable):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
+@@ -209,7 +204,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_unicode_funcs_get_empty (void)
+@@ -225,7 +220,7 @@
+ *
+ * Return value: (transfer full):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
+@@ -239,7 +234,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
+@@ -268,7 +263,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
+@@ -289,7 +284,7 @@
+ *
+ * Return value: (transfer none):
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void *
+ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
+@@ -305,7 +300,7 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ void
+ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
+@@ -324,7 +319,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
+@@ -340,7 +335,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
+@@ -400,7 +395,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
+@@ -422,7 +417,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ hb_bool_t
+ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
+@@ -443,7 +438,7 @@
+ *
+ * Return value:
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+ unsigned int
+ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+diff -uN gfx/harfbuzz/src_old/hb-unicode.h gfx/harfbuzz/src/hb-unicode.h
+--- gfx/harfbuzz/src_old/hb-unicode.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-unicode.h 2016-06-05 23:50:47.101562269 +0200
+@@ -174,23 +174,23 @@
+ /*
+ * just give me the best implementation you've got there.
+ */
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_default (void);
+
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_create (hb_unicode_funcs_t *parent);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_empty (void);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
+
+-void
++HB_EXTERN void
+ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key,
+ void * data,
+@@ -198,18 +198,18 @@
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key);
+
+
+-void
++HB_EXTERN void
+ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
+
+
+@@ -283,9 +283,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_combining_class_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -299,9 +299,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_eastasian_width_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -315,9 +315,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_general_category_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -331,9 +331,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_mirroring_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -347,9 +347,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_script_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -363,9 +363,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_compose_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -379,9 +379,9 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_decompose_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+@@ -395,47 +395,88 @@
+ *
+ *
+ *
+- * Since: 1.0
++ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_decompose_compatibility_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /* accessors */
+
+-hb_unicode_combining_class_t
++/**
++ * hb_unicode_combining_class:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_unicode_combining_class_t
+ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+-unsigned int
++/**
++ * hb_unicode_eastasian_width:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN unsigned int
+ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+-hb_unicode_general_category_t
++/**
++ * hb_unicode_general_category:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_unicode_general_category_t
+ hb_unicode_general_category (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+-hb_codepoint_t
++/**
++ * hb_unicode_mirroring:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_codepoint_t
+ hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+-hb_script_t
++/**
++ * hb_unicode_script:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_script_t
+ hb_unicode_script (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+-hb_bool_t
++/**
++ * hb_unicode_compose:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_bool_t
+ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab);
+-hb_bool_t
++
++/**
++ * hb_unicode_decompose:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN hb_bool_t
+ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b);
+
+-unsigned int
++/**
++ * hb_unicode_decompose_compatibility:
++ *
++ * Since: 0.9.2
++ **/
++HB_EXTERN unsigned int
+ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed);
+diff -uN gfx/harfbuzz/src_old/hb-unicode-private.hh gfx/harfbuzz/src/hb-unicode-private.hh
+--- gfx/harfbuzz/src_old/hb-unicode-private.hh 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-unicode-private.hh 2016-06-05 23:50:44.271576710 +0200
+@@ -199,6 +199,50 @@
+ }
+ }
+
++ /* Space estimates based on:
++ * http://www.unicode.org/charts/PDF/U2000.pdf
++ * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
++ */
++ enum space_t {
++ NOT_SPACE = 0,
++ SPACE_EM = 1,
++ SPACE_EM_2 = 2,
++ SPACE_EM_3 = 3,
++ SPACE_EM_4 = 4,
++ SPACE_EM_5 = 5,
++ SPACE_EM_6 = 6,
++ SPACE_EM_16 = 16,
++ SPACE_4_EM_18, /* 4/18th of an EM! */
++ SPACE,
++ SPACE_FIGURE,
++ SPACE_PUNCTUATION,
++ SPACE_NARROW,
++ };
++ static inline space_t
++ space_fallback_type (hb_codepoint_t u)
++ {
++ switch (u)
++ {
++ /* All GC=Zs chars that can use a fallback. */
++ default: return NOT_SPACE; /* Shouldn't happen. */
++ case 0x0020u: return SPACE; /* U+0020 SPACE */
++ case 0x00A0u: return SPACE; /* U+00A0 NO-BREAK SPACE */
++ case 0x2000u: return SPACE_EM_2; /* U+2000 EN QUAD */
++ case 0x2001u: return SPACE_EM; /* U+2001 EM QUAD */
++ case 0x2002u: return SPACE_EM_2; /* U+2002 EN SPACE */
++ case 0x2003u: return SPACE_EM; /* U+2003 EM SPACE */
++ case 0x2004u: return SPACE_EM_3; /* U+2004 THREE-PER-EM SPACE */
++ case 0x2005u: return SPACE_EM_4; /* U+2005 FOUR-PER-EM SPACE */
++ case 0x2006u: return SPACE_EM_6; /* U+2006 SIX-PER-EM SPACE */
++ case 0x2007u: return SPACE_FIGURE; /* U+2007 FIGURE SPACE */
++ case 0x2008u: return SPACE_PUNCTUATION; /* U+2008 PUNCTUATION SPACE */
++ case 0x2009u: return SPACE_EM_5; /* U+2009 THIN SPACE */
++ case 0x200Au: return SPACE_EM_16; /* U+200A HAIR SPACE */
++ case 0x202Fu: return SPACE_NARROW; /* U+202F NARROW NO-BREAK SPACE */
++ case 0x205Fu: return SPACE_4_EM_18; /* U+205F MEDIUM MATHEMATICAL SPACE */
++ case 0x3000u: return SPACE_EM; /* U+3000 IDEOGRAPHIC SPACE */
++ }
++ }
+
+ struct {
+ #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
+@@ -308,10 +352,14 @@
+ /* Misc */
+
+ #define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
+- (FLAG (gen_cat) & \
++ (FLAG_SAFE (gen_cat) & \
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+
++#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK(gen_cat) \
++ (FLAG_SAFE (gen_cat) & \
++ (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
++ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+
+ #endif /* HB_UNICODE_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-uniscribe.cc gfx/harfbuzz/src/hb-uniscribe.cc
+--- gfx/harfbuzz/src_old/hb-uniscribe.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-uniscribe.cc 2016-06-05 23:50:48.566554822 +0200
+@@ -486,14 +486,16 @@
+ LOGFONTW log_font;
+ HFONT hfont;
+ SCRIPT_CACHE script_cache;
++ double x_mult, y_mult; /* From LOGFONT space to HB space. */
+ };
+
+ static bool
+ populate_log_font (LOGFONTW *lf,
+- hb_font_t *font)
++ hb_font_t *font,
++ unsigned int font_size)
+ {
+ memset (lf, 0, sizeof (*lf));
+- lf->lfHeight = -font->y_scale;
++ lf->lfHeight = -font_size;
+ lf->lfCharSet = DEFAULT_CHARSET;
+
+ hb_face_t *face = font->face;
+@@ -513,9 +515,19 @@
+ if (unlikely (!data))
+ return NULL;
+
++ int font_size = font->face->get_upem (); /* Default... */
++ /* No idea if the following is even a good idea. */
++ if (font->y_ppem)
++ font_size = font->y_ppem;
++
++ if (font_size < 0)
++ font_size = -font_size;
++ data->x_mult = (double) font->x_scale / font_size;
++ data->y_mult = (double) font->y_scale / font_size;
++
+ data->hdc = GetDC (NULL);
+
+- if (unlikely (!populate_log_font (&data->log_font, font))) {
++ if (unlikely (!populate_log_font (&data->log_font, font, font_size))) {
+ DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
+ _hb_uniscribe_shaper_font_data_destroy (data);
+ return NULL;
+@@ -907,7 +919,7 @@
+
+ if (unlikely (items[i].a.fNoGlyphIndex))
+ FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
+- if (unlikely (hr == E_OUTOFMEMORY))
++ if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER))
+ {
+ if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+ FAIL ("Buffer resize failed");
+@@ -994,21 +1006,22 @@
+
+ /* The rest is crap. Let's store position info there for now. */
+ info->mask = advances[i];
+- info->var1.u32 = offsets[i].du;
+- info->var2.u32 = offsets[i].dv;
++ info->var1.i32 = offsets[i].du;
++ info->var2.i32 = offsets[i].dv;
+ }
+
+ /* Set glyph positions */
+ buffer->clear_positions ();
++ double x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+ for (unsigned int i = 0; i < glyphs_len; i++)
+ {
+ hb_glyph_info_t *info = &buffer->info[i];
+ hb_glyph_position_t *pos = &buffer->pos[i];
+
+ /* TODO vertical */
+- pos->x_advance = info->mask;
+- pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
+- pos->y_offset = info->var2.u32;
++ pos->x_advance = x_mult * (int32_t) info->mask;
++ pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
++ pos->y_offset = y_mult * info->var2.i32;
+ }
+
+ if (backward)
+diff -uN gfx/harfbuzz/src_old/hb-uniscribe.h gfx/harfbuzz/src/hb-uniscribe.h
+--- gfx/harfbuzz/src_old/hb-uniscribe.h 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-uniscribe.h 2016-06-05 23:50:49.730548897 +0200
+@@ -34,10 +34,10 @@
+ HB_BEGIN_DECLS
+
+
+-LOGFONTW *
++HB_EXTERN LOGFONTW *
+ hb_uniscribe_font_get_logfontw (hb_font_t *font);
+
+-HFONT
++HB_EXTERN HFONT
+ hb_uniscribe_font_get_hfont (hb_font_t *font);
+
+
+diff -uN gfx/harfbuzz/src_old/hb-utf-private.hh gfx/harfbuzz/src/hb-utf-private.hh
+--- gfx/harfbuzz/src_old/hb-utf-private.hh 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-utf-private.hh 2016-06-05 23:50:51.027542307 +0200
+@@ -29,14 +29,11 @@
+
+ #include "hb-private.hh"
+
+-template <typename T, bool validate=true> struct hb_utf_t;
+
+-
+-/* UTF-8 */
+-
+-template <>
+-struct hb_utf_t<uint8_t, true>
++struct hb_utf8_t
+ {
++ typedef uint8_t codepoint_t;
++
+ static inline const uint8_t *
+ next (const uint8_t *text,
+ const uint8_t *end,
+@@ -131,11 +128,10 @@
+ };
+
+
+-/* UTF-16 */
+-
+-template <>
+-struct hb_utf_t<uint16_t, true>
++struct hb_utf16_t
+ {
++ typedef uint16_t codepoint_t;
++
+ static inline const uint16_t *
+ next (const uint16_t *text,
+ const uint16_t *end,
+@@ -150,11 +146,11 @@
+ return text;
+ }
+
+- if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
++ if (likely (c <= 0xDBFFu && text < end))
+ {
+ /* High-surrogate in c */
+- hb_codepoint_t l;
+- if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
++ hb_codepoint_t l = *text;
++ if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
+ {
+ /* Low-surrogate in l */
+ *unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+@@ -174,8 +170,7 @@
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+- const uint16_t *end = text--;
+- hb_codepoint_t c = *text;
++ hb_codepoint_t c = *--text;
+
+ if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+ {
+@@ -183,14 +178,22 @@
+ return text;
+ }
+
+- if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
+- text--;
+-
+- if (likely (next (text, end, unicode, replacement) == end))
+- return text;
++ if (likely (c >= 0xDC00u && start < text))
++ {
++ /* Low-surrogate in c */
++ hb_codepoint_t h = text[-1];
++ if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
++ {
++ /* High-surrogate in h */
++ *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
++ text--;
++ return text;
++ }
++ }
+
++ /* Lonely / out-of-order surrogate. */
+ *unicode = replacement;
+- return end - 1;
++ return text;
+ }
+
+
+@@ -204,25 +207,20 @@
+ };
+
+
+-/* UTF-32 */
+-
+-template <bool validate>
+-struct hb_utf_t<uint32_t, validate>
++template <bool validate=true>
++struct hb_utf32_t
+ {
++ typedef uint32_t codepoint_t;
++
+ static inline const uint32_t *
+ next (const uint32_t *text,
+ const uint32_t *end HB_UNUSED,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+- hb_codepoint_t c = *text++;
+- if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
+- goto error;
+- *unicode = c;
+- return text;
+-
+- error:
+- *unicode = replacement;
++ hb_codepoint_t c = *unicode = *text++;
++ if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
++ *unicode = replacement;
+ return text;
+ }
+
+@@ -232,8 +230,10 @@
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+- next (text - 1, text, unicode, replacement);
+- return text - 1;
++ hb_codepoint_t c = *unicode = *--text;
++ if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
++ *unicode = replacement;
++ return text;
+ }
+
+ static inline unsigned int
+@@ -246,4 +246,37 @@
+ };
+
+
++struct hb_latin1_t
++{
++ typedef uint8_t codepoint_t;
++
++ static inline const uint8_t *
++ next (const uint8_t *text,
++ const uint8_t *end HB_UNUSED,
++ hb_codepoint_t *unicode,
++ hb_codepoint_t replacement HB_UNUSED)
++ {
++ *unicode = *text++;
++ return text;
++ }
++
++ static inline const uint8_t *
++ prev (const uint8_t *text,
++ const uint8_t *start HB_UNUSED,
++ hb_codepoint_t *unicode,
++ hb_codepoint_t replacement)
++ {
++ *unicode = *--text;
++ return text;
++ }
++
++ static inline unsigned int
++ strlen (const uint8_t *text)
++ {
++ unsigned int l = 0;
++ while (*text++) l++;
++ return l;
++ }
++};
++
+ #endif /* HB_UTF_PRIVATE_HH */
+diff -uN gfx/harfbuzz/src_old/hb-version.h gfx/harfbuzz/src/hb-version.h
+--- gfx/harfbuzz/src_old/hb-version.h 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-version.h 2016-06-05 23:50:52.292535893 +0200
+@@ -36,26 +36,26 @@
+ HB_BEGIN_DECLS
+
+
+-#define HB_VERSION_MAJOR 0
+-#define HB_VERSION_MINOR 9
+-#define HB_VERSION_MICRO 37
++#define HB_VERSION_MAJOR 1
++#define HB_VERSION_MINOR 1
++#define HB_VERSION_MICRO 3
+
+-#define HB_VERSION_STRING "0.9.37"
++#define HB_VERSION_STRING "1.1.3"
+
+ #define HB_VERSION_ATLEAST(major,minor,micro) \
+ ((major)*10000+(minor)*100+(micro) <= \
+ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
+
+
+-void
++HB_EXTERN void
+ hb_version (unsigned int *major,
+ unsigned int *minor,
+ unsigned int *micro);
+
+-const char *
++HB_EXTERN const char *
+ hb_version_string (void);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
+diff -uN gfx/harfbuzz/src_old/hb-version.h.in gfx/harfbuzz/src/hb-version.h.in
+--- gfx/harfbuzz/src_old/hb-version.h.in 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/hb-version.h.in 2016-06-05 23:50:53.575529376 +0200
+@@ -47,15 +47,15 @@
+ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
+
+
+-void
++HB_EXTERN void
+ hb_version (unsigned int *major,
+ unsigned int *minor,
+ unsigned int *micro);
+
+-const char *
++HB_EXTERN const char *
+ hb_version_string (void);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
+diff -uN gfx/harfbuzz/src_old/hb-warning.cc gfx/harfbuzz/src/hb-warning.cc
+--- gfx/harfbuzz/src_old/hb-warning.cc 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/hb-warning.cc 2016-06-05 23:50:54.795523196 +0200
+@@ -29,27 +29,11 @@
+
+
+ #if defined(HB_ATOMIC_INT_NIL)
+-#ifdef _MSC_VER
+-#pragma message("Could not find any system to define atomic_int macros, library may NOT be thread-safe")
+-#else
+-#warning "Could not find any system to define atomic_int macros, library may NOT be thread-safe"
+-#endif
++#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
++#error "Check hb-atomic-private.hh for possible resolutions."
+ #endif
+
+ #if defined(HB_MUTEX_IMPL_NIL)
+-#ifdef _MSC_VER
+-#pragma message("Could not find any system to define mutex macros, library may NOT be thread-safe")
+-#else
+-#warning "Could not find any system to define mutex macros, library may NOT be thread-safe"
+-#endif
+-#endif
+-
+-#if defined(HB_ATOMIC_INT_NIL) || defined(HB_MUTEX_IMPL_NIL)
+-#ifdef _MSC_VER
+-#pragma message("To suppress these warnings, define HB_NO_MT")
+-#else
+-#warning "To suppress these warnings, define HB_NO_MT"
++#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
++#error "Check hb-mutex-private.hh for possible resolutions."
+ #endif
+-#endif
+-
+-
+diff -uN gfx/harfbuzz/src_old/Makefile.am gfx/harfbuzz/src/Makefile.am
+--- gfx/harfbuzz/src_old/Makefile.am 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/Makefile.am 2016-06-05 23:47:56.984478616 +0200
+@@ -13,10 +13,16 @@
+ # The following warning options are useful for debugging: -Wpadded
+ #AM_CXXFLAGS =
+
++# Convenience targets:
++lib: $(BUILT_SOURCES) libharfbuzz.la
++fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
++
+ lib_LTLIBRARIES = libharfbuzz.la
+
+ HBCFLAGS =
+ HBLIBS =
++HBNONPCLIBS =
++HBDEPS =
+ HBSOURCES = \
+ hb-atomic-private.hh \
+ hb-blob.cc \
+@@ -36,11 +42,13 @@
+ hb-open-file-private.hh \
+ hb-open-type-private.hh \
+ hb-ot-cmap-table.hh \
++ hb-ot-glyf-table.hh \
+ hb-ot-head-table.hh \
+ hb-ot-hhea-table.hh \
+ hb-ot-hmtx-table.hh \
+ hb-ot-maxp-table.hh \
+ hb-ot-name-table.hh \
++ hb-ot-os2-table.hh \
+ hb-ot-tag.cc \
+ hb-private.hh \
+ hb-set-private.hh \
+@@ -90,6 +98,7 @@
+ hb-ot-shape.cc \
+ hb-ot-shape-complex-arabic.cc \
+ hb-ot-shape-complex-arabic-fallback.hh \
++ hb-ot-shape-complex-arabic-private.hh \
+ hb-ot-shape-complex-arabic-table.hh \
+ hb-ot-shape-complex-arabic-win1256.hh \
+ hb-ot-shape-complex-default.cc \
+@@ -101,10 +110,12 @@
+ hb-ot-shape-complex-indic-table.cc \
+ hb-ot-shape-complex-myanmar.cc \
+ hb-ot-shape-complex-myanmar-machine.hh \
+- hb-ot-shape-complex-sea.cc \
+- hb-ot-shape-complex-sea-machine.hh \
+ hb-ot-shape-complex-thai.cc \
+ hb-ot-shape-complex-tibetan.cc \
++ hb-ot-shape-complex-use.cc \
++ hb-ot-shape-complex-use-machine.hh \
++ hb-ot-shape-complex-use-private.hh \
++ hb-ot-shape-complex-use-table.cc \
+ hb-ot-shape-complex-private.hh \
+ hb-ot-shape-normalize-private.hh \
+ hb-ot-shape-normalize.cc \
+@@ -127,12 +138,13 @@
+
+ if HAVE_PTHREAD
+ HBCFLAGS += $(PTHREAD_CFLAGS)
+-HBLIBS += $(PTHREAD_LIBS)
++HBNONPCLIBS += $(PTHREAD_LIBS)
+ endif
+
+ if HAVE_GLIB
+ HBCFLAGS += $(GLIB_CFLAGS)
+ HBLIBS += $(GLIB_LIBS)
++HBDEPS += $(GLIB_DEPS)
+ HBSOURCES += hb-glib.cc
+ HBHEADERS += hb-glib.h
+ endif
+@@ -140,6 +152,12 @@
+ if HAVE_FREETYPE
+ HBCFLAGS += $(FREETYPE_CFLAGS)
+ HBLIBS += $(FREETYPE_LIBS)
++# XXX
++# The following creates a recursive dependency on FreeType if FreeType is
++# built with HarfBuzz support enabled. Newer pkg-config handles that just
++# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes. Remove
++# in a year or two, or otherwise work around it...
++#HBDEPS += $(FREETYPE_DEPS)
+ HBSOURCES += hb-ft.cc
+ HBHEADERS += hb-ft.h
+ endif
+@@ -147,20 +165,21 @@
+ if HAVE_GRAPHITE2
+ HBCFLAGS += $(GRAPHITE2_CFLAGS)
+ HBLIBS += $(GRAPHITE2_LIBS)
++HBDEPS += $(GRAPHITE2_DEPS)
+ HBSOURCES += hb-graphite2.cc
+ HBHEADERS += hb-graphite2.h
+ endif
+
+ if HAVE_UNISCRIBE
+ HBCFLAGS += $(UNISCRIBE_CFLAGS)
+-HBLIBS += $(UNISCRIBE_LIBS)
++HBNONPCLIBS += $(UNISCRIBE_LIBS)
+ HBSOURCES += hb-uniscribe.cc
+ HBHEADERS += hb-uniscribe.h
+ endif
+
+ if HAVE_CORETEXT
+ HBCFLAGS += $(CORETEXT_CFLAGS)
+-HBLIBS += $(CORETEXT_LIBS)
++HBNONPCLIBS += $(CORETEXT_LIBS)
+ HBSOURCES += hb-coretext.cc
+ HBHEADERS += hb-coretext.h
+ endif
+@@ -176,6 +195,8 @@
+
+ # Put the library together
+
++HBLIBS += $(HBNONPCLIBS)
++
+ if OS_WIN32
+ export_symbols = -export-symbols harfbuzz.def
+ harfbuzz_def_dependency = harfbuzz.def
+@@ -200,6 +221,22 @@
+ pkgconfig_DATA = harfbuzz.pc
+ EXTRA_DIST += harfbuzz.pc.in
+
++FUZZING_CPPFLAGS= \
++ -DHB_MAX_NESTING_LEVEL=3 \
++ -DHB_SANITIZE_MAX_EDITS=3 \
++ -DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
++ -DHB_BUFFER_MAX_LEN_MIN=8 \
++ -DHB_BUFFER_MAX_LEN_DEFAULT=128 \
++ $(NULL)
++EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
++libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
++libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
++libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
++libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
++libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
++EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
++CLEANFILES += libharfbuzz-fuzzing.la
++
+ if HAVE_ICU
+ lib_LTLIBRARIES += libharfbuzz-icu.la
+ libharfbuzz_icu_la_SOURCES = hb-icu.cc
+@@ -250,6 +287,8 @@
+ -e 's@%exec_prefix%@$(exec_prefix)@g' \
+ -e 's@%libdir%@$(libdir)@g' \
+ -e 's@%includedir%@$(includedir)@g' \
++ -e 's@%libs_private%@$(HBNONPCLIBS)@g' \
++ -e 's@%requires_private%@$(HBDEPS)@g' \
+ -e 's@%VERSION%@$(VERSION)@g' \
+ "$<" > "$@" \
+ || ($(RM) "$@"; false)
+@@ -264,7 +303,7 @@
+ $(EGREP) '^hb_.* \(' | \
+ sed -e 's/ (.*//' | \
+ LANG=C sort; \
+- echo LIBRARY libharfbuzz-$(HB_VERSION_MAJOR).dll; \
++ echo LIBRARY libharfbuzz-0.dll; \
+ ) >"$@"
+ @ ! grep -q hb_ERROR "$@" \
+ || ($(RM) "$@"; false)
+@@ -273,29 +312,34 @@
+ GENERATORS = \
+ gen-arabic-table.py \
+ gen-indic-table.py \
++ gen-use-table.py \
+ $(NULL)
+ EXTRA_DIST += $(GENERATORS)
+
+-unicode-tables: arabic-table indic-table
+-
+-indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
+- $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
+- || ($(RM) hb-ot-shape-complex-indic-table.cc; false)
++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)
+
++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)
++
++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)
++
+ built-sources: $(BUILT_SOURCES)
+
+-.PHONY: unicode-tables arabic-table indic-table built-sources
++.PHONY: unicode-tables arabic-table indic-table use-table built-sources
+
+ RAGEL_GENERATED = \
+ $(srcdir)/hb-buffer-deserialize-json.hh \
+ $(srcdir)/hb-buffer-deserialize-text.hh \
+ $(srcdir)/hb-ot-shape-complex-indic-machine.hh \
+ $(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
+- $(srcdir)/hb-ot-shape-complex-sea-machine.hh \
++ $(srcdir)/hb-ot-shape-complex-use-machine.hh \
+ $(NULL)
+ BUILT_SOURCES += $(RAGEL_GENERATED)
+ EXTRA_DIST += \
+@@ -303,7 +347,7 @@
+ hb-buffer-deserialize-text.rl \
+ hb-ot-shape-complex-indic-machine.rl \
+ hb-ot-shape-complex-myanmar-machine.rl \
+- hb-ot-shape-complex-sea-machine.rl \
++ hb-ot-shape-complex-use-machine.rl \
+ $(NULL)
+ MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
+ $(srcdir)/%.hh: $(srcdir)/%.rl
+@@ -349,7 +393,14 @@
+ check-symbols.sh \
+ $(NULL)
+
+-TESTS = $(dist_check_SCRIPTS)
++check_PROGRAMS = \
++ test-ot-tag \
++ $(NULL)
++test_ot_tag_SOURCES = hb-ot-tag.cc
++test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
++test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
++
++TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
+ TESTS_ENVIRONMENT = \
+ srcdir="$(srcdir)" \
+ MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
+@@ -360,7 +411,7 @@
+ if HAVE_INTROSPECTION
+
+ -include $(INTROSPECTION_MAKEFILE)
+-INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
++INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
+ INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
+ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+ INTROSPECTION_SCANNER_ENV = CC="$(CC)"
+@@ -376,6 +427,7 @@
+ -DHB_OT_H_IN \
+ -DHB_GOBJECT_H \
+ -DHB_GOBJECT_H_IN \
++ -DHB_EXTERN= \
+ $(NULL)
+ HarfBuzz_0_0_gir_LIBS = \
+ libharfbuzz.la \
+diff -uN gfx/harfbuzz/src_old/Makefile.in gfx/harfbuzz/src/Makefile.in
+--- gfx/harfbuzz/src_old/Makefile.in 2016-05-10 22:26:55.000000000 +0200
++++ gfx/harfbuzz/src/Makefile.in 1970-01-01 01:00:00.000000000 +0100
+@@ -1,31 +0,0 @@
+-#
+-# Copyright (C) 2010 Mozilla Foundation
+-#
+-# This is used to integrate the HarfBuzz library with the GNU build.
+-#
+-# 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.
+-#
+-# GNU author(s): Jonathan Kew
+-#
+-
+-include $(topsrcdir)/config/rules.mk
+-
+-# Cancel the effect of the -DDEBUG macro if present,
+-# because harfbuzz uses that name for its own purposes
+-COMPILE_CXXFLAGS += -UDEBUG
+diff -uN gfx/harfbuzz/src_old/moz.build gfx/harfbuzz/src/moz.build
+--- gfx/harfbuzz/src_old/moz.build 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/moz.build 2016-06-05 23:50:58.630503774 +0200
+@@ -29,7 +29,7 @@
+ 'hb-common.cc', # error: use of undeclared identifier 'strdup'
+ 'hb-ot-shape-complex-hangul.cc', # error: redefinition of enumerator 'NONE'
+ 'hb-ot-shape-complex-indic.cc', # error: redefinition of enumerator 'INIT'
+- 'hb-ot-shape-complex-sea.cc', # error: redefinition of 'basic_features'
++ 'hb-ot-shape-complex-use.cc', # error: redefinition of 'basic_features'
+ 'hb-ot-shape.cc', # error: functions that differ only in their return type cannot be overloaded
+ 'hb-shape-plan.cc', # error: redefinition of 'hb_ot_shaper_face_data_ensure'
+ ]
+@@ -48,6 +48,7 @@
+ 'hb-ot-shape-complex-myanmar.cc',
+ 'hb-ot-shape-complex-thai.cc',
+ 'hb-ot-shape-complex-tibetan.cc',
++ 'hb-ot-shape-complex-use-table.cc',
+ 'hb-ot-shape-fallback.cc',
+ 'hb-ot-shape-normalize.cc',
+ 'hb-ot-tag.cc',
+@@ -58,7 +59,8 @@
+ 'hb-warning.cc',
+ ]
+
+-MSVC_ENABLE_PGO = True
++# We allow warnings for third-party code that can be updated from upstream.
++FAIL_ON_WARNINGS = True
+
+ FINAL_LIBRARY = 'gkmedias'
+
+@@ -67,3 +69,6 @@
+ DEFINES['HAVE_OT'] = 1
+ DEFINES['HB_NO_MT'] = True
+ DEFINES['HB_NO_UNICODE_FUNCS'] = True
++# Cancel the effect of the -DDEBUG macro if present,
++# because harfbuzz uses that name for its own purposes
++DEFINES['DEBUG'] = False
+diff -uN gfx/harfbuzz/src_old/sample.py gfx/harfbuzz/src/sample.py
+--- gfx/harfbuzz/src_old/sample.py 1970-01-01 01:00:00.000000000 +0100
++++ gfx/harfbuzz/src/sample.py 2016-06-05 23:50:59.856497586 +0200
+@@ -0,0 +1,58 @@
++#!/usr/bin/python
++# -*- coding: utf-8 -*-
++
++from __future__ import print_function
++import sys
++from gi.repository import HarfBuzz as hb
++from gi.repository import GLib
++
++# Python 2/3 compatibility
++try:
++ unicode
++except NameError:
++ unicode = str
++
++def tounicode(s, encoding='utf-8'):
++ if not isinstance(s, unicode):
++ return s.decode(encoding)
++ else:
++ return s
++
++fontdata = open (sys.argv[1], 'rb').read ()
++text = tounicode(sys.argv[2])
++# Need to create GLib.Bytes explicitly until this bug is fixed:
++# https://bugzilla.gnome.org/show_bug.cgi?id=729541
++blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
++face = hb.face_create (blob, 0)
++del blob
++font = hb.font_create (face)
++upem = hb.face_get_upem (face)
++del face
++hb.font_set_scale (font, upem, upem)
++#hb.ft_font_set_funcs (font)
++hb.ot_font_set_funcs (font)
++
++buf = hb.buffer_create ()
++class Debugger(object):
++ def message (self, buf, font, msg, data, _x_what_is_this):
++ print(msg)
++ return True
++debugger = Debugger()
++hb.buffer_set_message_func (buf, debugger.message, 1, 0)
++hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
++hb.buffer_guess_segment_properties (buf)
++
++hb.shape (font, buf, [])
++del font
++
++infos = hb.buffer_get_glyph_infos (buf)
++positions = hb.buffer_get_glyph_positions (buf)
++
++for info,pos in zip(infos, positions):
++ gid = info.codepoint
++ cluster = info.cluster
++ x_advance = pos.x_advance
++ x_offset = pos.x_offset
++ y_offset = pos.y_offset
++
++ print("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
+diff -uN gfx/harfbuzz/src_old/test.cc gfx/harfbuzz/src/test.cc
+--- gfx/harfbuzz/src_old/test.cc 2016-05-10 22:26:56.000000000 +0200
++++ gfx/harfbuzz/src/test.cc 2016-06-05 23:51:04.705473120 +0200
+@@ -120,7 +120,7 @@
+ info->cluster,
+ info->codepoint,
+ pos->x_offset,
+- pos->x_offset,
++ pos->y_offset,
+ pos->x_advance,
+ pos->y_advance);
+
diff --git a/libre/icecat/icecat-fixed-loading-icon.png b/libre/icecat/icecat-fixed-loading-icon.png
new file mode 100644
index 000000000..55f25e591
--- /dev/null
+++ b/libre/icecat/icecat-fixed-loading-icon.png
Binary files differ
diff --git a/libre/icecat/icecat-gtk3-20.patch b/libre/icecat/icecat-gtk3-20.patch
new file mode 100644
index 000000000..781604a47
--- /dev/null
+++ b/libre/icecat/icecat-gtk3-20.patch
@@ -0,0 +1,1638 @@
+ widget/gtk/gtk3drawing.c | 653 +++++++++++++++++++++++++++-------------
+ widget/gtk/gtkdrawing.h | 17 ++
+ widget/gtk/mozgtk/mozgtk.c | 13 +
+ widget/gtk/nsLookAndFeel.cpp | 99 +++---
+ widget/gtk/nsNativeThemeGTK.cpp | 18 +-
+ 5 files changed, 545 insertions(+), 255 deletions(-)
+
+diff --git c/widget/gtk/gtk3drawing.c i/widget/gtk/gtk3drawing.c
+index a716b8d..d7ee658 100644
+--- c/widget/gtk/gtk3drawing.c
++++ i/widget/gtk/gtk3drawing.c
+@@ -17,32 +17,78 @@
+
+ #include <math.h>
+
++#define MOZ_WIDGET_STYLES 4
++
++typedef struct {
++ GtkWidget* widget;
++
++ union {
++ struct {
++ GtkStyleContext* style;
++ GtkStyleContext* styleSelection;
++ } entry;
++
++ struct {
++ GtkStyleContext* style;
++ } button;
++
++ struct {
++ GtkStyleContext* style;
++ GtkStyleContext* styleTrough;
++ GtkStyleContext* styleSlider;
++ } scroll;
++
++ struct {
++ GtkStyleContext* style;
++ GtkStyleContext* styleCheck;
++ GtkStyleContext* styleLabel;
++ } check;
++
++ struct {
++ GtkStyleContext* style;
++ GtkStyleContext* styleTrough;
++ GtkStyleContext* styleProgress;
++ } progress;
++
++ struct {
++ GtkStyleContext* style;
++ GtkStyleContext* styleEntry;
++ GtkStyleContext* styleButtonUp;
++ GtkStyleContext* styleButtonDown;
++ } spin;
++
++ struct {
++ GtkStyleContext* style[MOZ_WIDGET_STYLES];
++ } all;
++ };
++} MozGtkWidget;
++
+ static GtkWidget* gProtoWindow;
+ static GtkWidget* gProtoLayout;
+-static GtkWidget* gButtonWidget;
++static MozGtkWidget gButton;
+ static GtkWidget* gToggleButtonWidget;
+ static GtkWidget* gButtonArrowWidget;
+-static GtkWidget* gCheckboxWidget;
+-static GtkWidget* gRadiobuttonWidget;
+-static GtkWidget* gHorizScrollbarWidget;
+-static GtkWidget* gVertScrollbarWidget;
+-static GtkWidget* gSpinWidget;
++static MozGtkWidget gCheckbox;
++static MozGtkWidget gRadiobutton;
++static MozGtkWidget gVertScrollbar;
++static MozGtkWidget gHorizScrollbar;
++static MozGtkWidget gSpin;
+ static GtkWidget* gHScaleWidget;
+ static GtkWidget* gVScaleWidget;
+-static GtkWidget* gEntryWidget;
++static MozGtkWidget gEntry;
+ static GtkWidget* gComboBoxWidget;
+ static GtkWidget* gComboBoxButtonWidget;
+ static GtkWidget* gComboBoxArrowWidget;
+ static GtkWidget* gComboBoxSeparatorWidget;
+ static GtkWidget* gComboBoxEntryWidget;
+-static GtkWidget* gComboBoxEntryTextareaWidget;
++static MozGtkWidget gComboBoxEntryTextarea;
+ static GtkWidget* gComboBoxEntryButtonWidget;
+ static GtkWidget* gComboBoxEntryArrowWidget;
+ static GtkWidget* gHandleBoxWidget;
+ static GtkWidget* gToolbarWidget;
+ static GtkWidget* gFrameWidget;
+ static GtkWidget* gStatusbarWidget;
+-static GtkWidget* gProgressWidget;
++static MozGtkWidget gProgressBar;
+ static GtkWidget* gTabWidget;
+ static GtkWidget* gTooltipWidget;
+ static GtkWidget* gMenuBarWidget;
+@@ -78,6 +124,37 @@ static gboolean is_initialized;
+ #define GTK_STATE_FLAG_CHECKED (1 << 11)
+ #endif
+
++void moz_gtk_widget_free(MozGtkWidget *aMozWidget)
++{
++ // This was removed as a child of gProtoWindow
++ if (aMozWidget->widget) {
++ aMozWidget->widget = NULL;
++ }
++
++ for(int i = 0; i < MOZ_WIDGET_STYLES; i++) {
++ if (aMozWidget->all.style[i]) {
++ g_object_unref(aMozWidget->all.style[i]);
++ aMozWidget->all.style[i] = NULL;
++ }
++ }
++}
++
++// TODO - weak dep!! (dlsym)
++#if GTK_CHECK_VERSION(3, 19, 2)
++#define moz_gtk_path_set_class_name gtk_widget_path_iter_set_object_name
++#else
++#define moz_gtk_path_set_class_name gtk_widget_path_iter_add_class
++#endif
++//gtk_widget_path_iter_get_state
++
++static void
++moz_gtk_get_style_border(GtkStyleContext* style, GtkStateFlags state_flags,
++ GtkBorder *border);
++
++static void
++moz_gtk_get_style_padding(GtkStyleContext* style, GtkStateFlags state_flags,
++ GtkBorder *padding);
++
+ static GtkStateFlags
+ GetStateFlagsFromGtkWidgetState(GtkWidgetState* state)
+ {
+@@ -97,6 +174,41 @@ GetStateFlagsFromGtkWidgetState(GtkWidgetState* state)
+ return stateFlags;
+ }
+
++GtkStyleContext *
++moz_gtk_style_create(GtkCssNode *node, GtkStyleContext *parent)
++{
++ GtkWidgetPath *path;
++ GtkStyleContext *context;
++
++ if (parent)
++ path = gtk_widget_path_copy (gtk_style_context_get_path (parent));
++ else
++ path = gtk_widget_path_new ();
++
++ gtk_widget_path_append_type (path, node->type);
++ if (node->name)
++ moz_gtk_path_set_class_name(path, -1, node->name);
++ if (node->class1)
++ gtk_widget_path_iter_add_class(path, -1, node->class1);
++ if (node->class2)
++ gtk_widget_path_iter_add_class(path, -1, node->class2);
++
++ context = gtk_style_context_new ();
++ gtk_style_context_set_path (context, path);
++ gtk_style_context_set_parent (context, parent);
++
++ if(!gtk_check_version(3, 14, 0)) {
++ /* Unfortunately, we have to explicitly set the state again here
++ * for it to take effect
++ */
++ gtk_style_context_set_state (context, gtk_widget_path_iter_get_state (path, -1));
++ }
++
++ gtk_widget_path_unref (path);
++
++ return context;
++}
++
+ /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
+ that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
+ things they may want to do. */
+@@ -141,9 +253,16 @@ setup_widget_prototype(GtkWidget* widget)
+ static gint
+ ensure_button_widget()
+ {
+- if (!gButtonWidget) {
+- gButtonWidget = gtk_button_new_with_label("M");
+- setup_widget_prototype(gButtonWidget);
++ if (!gButton.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_BUTTON, "button", NULL, NULL }
++ };
++
++ gButton.widget = gtk_button_new_with_label("M");
++ setup_widget_prototype(gButton.widget);
++ gtk_widget_show(gButton.widget);
++
++ gButton.button.style = moz_gtk_style_create(&path[0], NULL);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -195,9 +314,21 @@ ensure_button_arrow_widget()
+ static gint
+ ensure_checkbox_widget()
+ {
+- if (!gCheckboxWidget) {
+- gCheckboxWidget = gtk_check_button_new_with_label("M");
+- setup_widget_prototype(gCheckboxWidget);
++ if (!gCheckbox.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_TOGGLE_BUTTON, "checkbutton", NULL, NULL },
++ { G_TYPE_NONE, "check", NULL, NULL },
++ { G_TYPE_NONE, "label", NULL, NULL }
++ };
++
++ gCheckbox.widget = gtk_check_button_new_with_label("M");
++ setup_widget_prototype(gCheckbox.widget);
++
++ gCheckbox.check.style = moz_gtk_style_create(&path[0], NULL);
++ gCheckbox.check.styleCheck = moz_gtk_style_create(&path[1],
++ gCheckbox.check.style);
++ gCheckbox.check.styleLabel = moz_gtk_style_create(&path[2],
++ gCheckbox.check.style);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -205,9 +336,21 @@ ensure_checkbox_widget()
+ static gint
+ ensure_radiobutton_widget()
+ {
+- if (!gRadiobuttonWidget) {
+- gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
+- setup_widget_prototype(gRadiobuttonWidget);
++ if (!gRadiobutton.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_TOGGLE_BUTTON, "radiobutton", NULL, NULL },
++ { G_TYPE_NONE, "radio", NULL, NULL },
++ { G_TYPE_NONE, "label", NULL, NULL }
++ };
++
++ gRadiobutton.widget = gtk_radio_button_new_with_label(NULL, "M");
++ setup_widget_prototype(gRadiobutton.widget);
++
++ gRadiobutton.check.style = moz_gtk_style_create(&path[0], NULL);
++ gRadiobutton.check.styleCheck = moz_gtk_style_create(&path[1],
++ gRadiobutton.check.style);
++ gRadiobutton.check.styleLabel = moz_gtk_style_create(&path[2],
++ gRadiobutton.check.style);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -215,13 +358,31 @@ ensure_radiobutton_widget()
+ static gint
+ ensure_scrollbar_widget()
+ {
+- if (!gVertScrollbarWidget) {
+- gVertScrollbarWidget = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
+- setup_widget_prototype(gVertScrollbarWidget);
+- }
+- if (!gHorizScrollbarWidget) {
+- gHorizScrollbarWidget = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
+- setup_widget_prototype(gHorizScrollbarWidget);
++ if (!gVertScrollbar.widget && !gHorizScrollbar.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_SCROLLBAR, "scrollbar", "horizontal", NULL },
++ { GTK_TYPE_SCROLLBAR, "scrollbar", "vertical", NULL },
++ { GTK_TYPE_SCROLLBAR, "trough", NULL, NULL },
++ { GTK_TYPE_SCROLLBAR, "slider", NULL, NULL }
++ };
++
++ gVertScrollbar.widget = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
++ setup_widget_prototype(gVertScrollbar.widget);
++
++ gVertScrollbar.scroll.style = moz_gtk_style_create(path+1, NULL);
++ gVertScrollbar.scroll.styleTrough = moz_gtk_style_create(path+2,
++ gVertScrollbar.scroll.style);
++ gVertScrollbar.scroll.styleSlider = moz_gtk_style_create(path+3,
++ gVertScrollbar.scroll.styleTrough);
++
++ gHorizScrollbar.widget = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
++ setup_widget_prototype(gHorizScrollbar.widget);
++
++ gHorizScrollbar.scroll.style = moz_gtk_style_create(path, NULL);
++ gHorizScrollbar.scroll.styleTrough = moz_gtk_style_create(path+2,
++ gHorizScrollbar.scroll.style);
++ gHorizScrollbar.scroll.styleSlider = moz_gtk_style_create(path+3,
++ gHorizScrollbar.scroll.styleTrough);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -229,11 +390,24 @@ ensure_scrollbar_widget()
+ static gint
+ ensure_spin_widget()
+ {
+- if (!gSpinWidget) {
+- gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
+- setup_widget_prototype(gSpinWidget);
+- }
+- return MOZ_GTK_SUCCESS;
++ if (!gSpin.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_SPIN_BUTTON, "spinbutton", "horizontal", NULL },
++ { GTK_TYPE_SPIN_BUTTON, "spinbutton", "vertical", NULL },
++ { GTK_TYPE_ENTRY, "entry", NULL, NULL },
++ { G_TYPE_NONE, "button", "up", NULL },
++ { G_TYPE_NONE, "button", "down", NULL }
++ };
++
++ gSpin.widget = gtk_spin_button_new(NULL, 1, 0);
++ setup_widget_prototype(gSpin.widget);
++
++ gSpin.spin.style = moz_gtk_style_create(path, NULL);
++ gSpin.spin.styleButtonUp = moz_gtk_style_create(path+3, gSpin.spin.style);
++ gSpin.spin.styleButtonDown = moz_gtk_style_create(path+4, gSpin.spin.style);
++ gSpin.spin.styleEntry = moz_gtk_style_create(path+2, gSpin.spin.style);
++ }
++ return MOZ_GTK_SUCCESS;
+ }
+
+ static gint
+@@ -253,9 +427,19 @@ ensure_scale_widget()
+ static gint
+ ensure_entry_widget()
+ {
+- if (!gEntryWidget) {
+- gEntryWidget = gtk_entry_new();
+- setup_widget_prototype(gEntryWidget);
++ if (!gEntry.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_ENTRY, "entry", NULL, NULL },
++ { G_TYPE_NONE, "selection", NULL, NULL }
++ };
++
++ gEntry.widget = gtk_entry_new();
++ setup_widget_prototype(gEntry.widget);
++ gtk_widget_show(gEntry.widget);
++
++ gEntry.entry.style = moz_gtk_style_create(&path[0], NULL);
++ gEntry.entry.styleSelection = moz_gtk_style_create(&path[1],
++ gEntry.entry.style);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -387,9 +571,9 @@ moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gComboBoxEntryButtonWidget);
+ } else if (GTK_IS_ENTRY(widget)) {
+- gComboBoxEntryTextareaWidget = widget;
++ gComboBoxEntryTextarea.widget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+- (gpointer) &gComboBoxEntryTextareaWidget);
++ (gpointer) &gComboBoxEntryTextarea.widget);
+ } else
+ return;
+ gtk_widget_realize(widget);
+@@ -411,7 +595,7 @@ ensure_combo_box_entry_widgets()
+ {
+ GtkWidget* buttonChild;
+
+- if (gComboBoxEntryTextareaWidget &&
++ if (gComboBoxEntryTextarea.widget &&
+ gComboBoxEntryButtonWidget &&
+ gComboBoxEntryArrowWidget)
+ return MOZ_GTK_SUCCESS;
+@@ -427,9 +611,9 @@ ensure_combo_box_entry_widgets()
+ moz_gtk_get_combo_box_entry_inner_widgets,
+ NULL);
+
+- if (!gComboBoxEntryTextareaWidget) {
++ if (!gComboBoxEntryTextarea.widget) {
+ ensure_entry_widget();
+- gComboBoxEntryTextareaWidget = gEntryWidget;
++ gComboBoxEntryTextarea.widget = gEntry.widget;
+ }
+
+ if (gComboBoxEntryButtonWidget) {
+@@ -528,9 +712,21 @@ ensure_tab_widget()
+ static gint
+ ensure_progress_widget()
+ {
+- if (!gProgressWidget) {
+- gProgressWidget = gtk_progress_bar_new();
+- setup_widget_prototype(gProgressWidget);
++ if (!gProgressBar.widget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_LABEL, "progressbar", NULL, NULL },
++ { G_TYPE_NONE, "trough", NULL, NULL },
++ { G_TYPE_NONE, "progress", NULL, NULL },
++ };
++
++ gProgressBar.widget = gtk_progress_bar_new();
++ setup_widget_prototype(gProgressBar.widget);
++
++ gProgressBar.progress.style = moz_gtk_style_create(&path[0], NULL);
++ gProgressBar.progress.styleTrough = moz_gtk_style_create(&path[1],
++ gProgressBar.progress.style);
++ gProgressBar.progress.styleProgress = moz_gtk_style_create(&path[2],
++ gProgressBar.progress.styleTrough);
+ }
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -636,6 +832,11 @@ static gint
+ ensure_check_menu_item_widget()
+ {
+ if (!gCheckMenuItemWidget) {
++ GtkCssNode path[] = {
++ { GTK_TYPE_CHECK_MENU_ITEM, "menuitem", NULL, NULL },
++ { G_TYPE_NONE, "check", NULL, NULL }
++ };
++
+ ensure_menu_popup_widget();
+ gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M");
+ gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
+@@ -757,7 +958,7 @@ moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
+ {
+ ensure_checkbox_widget();
+
+- gtk_widget_style_get (gCheckboxWidget,
++ gtk_widget_style_get (gCheckbox.widget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+@@ -770,7 +971,7 @@ moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
+ {
+ ensure_radiobutton_widget();
+
+- gtk_widget_style_get (gRadiobuttonWidget,
++ gtk_widget_style_get (gRadiobutton.widget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+@@ -783,13 +984,12 @@ moz_gtk_get_focus_outline_size(gint* focus_h_width, gint* focus_v_width)
+ {
+ GtkBorder border;
+ GtkBorder padding;
+- GtkStyleContext *style;
++ GtkStyleContext* style = gEntry.entry.style;
+
+ ensure_entry_widget();
+- style = gtk_widget_get_style_context(gEntryWidget);
+
+- gtk_style_context_get_border(style, 0, &border);
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+ *focus_h_width = border.left + padding.left;
+ *focus_v_width = border.top + padding.top;
+ return MOZ_GTK_SUCCESS;
+@@ -826,7 +1026,7 @@ moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left,
+ GtkBorder* default_outside_border;
+
+ ensure_button_widget();
+- gtk_widget_style_get(gButtonWidget,
++ gtk_widget_style_get(gButton.widget,
+ "default-outside-border", &default_outside_border,
+ NULL);
+
+@@ -849,7 +1049,7 @@ moz_gtk_button_get_default_border(gint* border_top, gint* border_left,
+ GtkBorder* default_border;
+
+ ensure_button_widget();
+- gtk_widget_style_get(gButtonWidget,
++ gtk_widget_style_get(gButton.widget,
+ "default-border", &default_border,
+ NULL);
+
+@@ -940,7 +1140,7 @@ moz_gtk_button_paint(cairo_t *cr, GdkRectangle* rect,
+
+ if (state->focused) {
+ GtkBorder border;
+- gtk_style_context_get_border(style, state_flags, &border);
++ moz_gtk_get_style_border(style, state_flags, &border);
+ x += border.left;
+ y += border.top;
+ width -= (border.left + border.right);
+@@ -961,15 +1161,14 @@ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
+ gint indicator_size, indicator_spacing;
+ gint x, y, width, height;
+ gint focus_x, focus_y, focus_width, focus_height;
+- GtkWidget *w;
+- GtkStyleContext *style;
++ MozGtkWidget *w;
+
+ if (isradio) {
+ moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
+- w = gRadiobuttonWidget;
++ w = &gRadiobutton;
+ } else {
+ moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
+- w = gCheckboxWidget;
++ w = &gCheckbox;
+ }
+
+ // XXX we should assert rect->height >= indicator_size too
+@@ -988,11 +1187,9 @@ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
+ focus_width = width + 2 * indicator_spacing;
+ focus_height = height + 2 * indicator_spacing;
+
+- style = gtk_widget_get_style_context(w);
+-
+- gtk_widget_set_sensitive(w, !state->disabled);
+- gtk_widget_set_direction(w, direction);
+- gtk_style_context_save(style);
++ gtk_widget_set_sensitive(w->widget, !state->disabled);
++ gtk_widget_set_direction(w->widget, direction);
++ gtk_style_context_save(w->check.styleCheck);
+
+ if (selected)
+ state_flags |= checkbox_check_state;
+@@ -1000,13 +1197,15 @@ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
+ if (inconsistent)
+ state_flags |= GTK_STATE_FLAG_INCONSISTENT;
+
+- gtk_style_context_set_state(style, state_flags);
++ gtk_style_context_set_state(w->check.styleCheck, state_flags);
++
++ gtk_render_background(w->check.styleCheck, cr, x, y, width, height);
++ gtk_render_frame(w->check.styleCheck, cr, x, y, width, height);
+
+ if (isradio) {
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
+- gtk_render_option(style, cr, x, y, width, height);
++ gtk_render_option(w->check.styleCheck, cr, x, y, width, height);
+ if (state->focused) {
+- gtk_render_focus(style, cr, focus_x, focus_y,
++ gtk_render_focus(w->check.styleCheck, cr, focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+@@ -1015,15 +1214,14 @@ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
+ * 'indeterminate' type on checkboxes. In GTK, the shadow type
+ * must also be changed for the state to be drawn.
+ */
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
+- gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), inconsistent);
+- gtk_render_check(style, cr, x, y, width, height);
++ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(w->widget), inconsistent);
++ gtk_render_check(w->check.styleCheck, cr, x, y, width, height);
+ if (state->focused) {
+- gtk_render_focus(style, cr,
++ gtk_render_focus(w->check.styleCheck, cr,
+ focus_x, focus_y, focus_width, focus_height);
+ }
+ }
+- gtk_style_context_restore(style);
++ gtk_style_context_restore(w->check.styleCheck);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1040,8 +1238,8 @@ calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
+ style = gtk_widget_get_style_context(button);
+
+ /* This mirrors gtkbutton's child positioning */
+- gtk_style_context_get_border(style, 0, &border);
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+
+ inner_rect->x = rect->x + border.left + padding.left;
+ inner_rect->y = rect->y + padding.top + border.top;
+@@ -1107,9 +1305,9 @@ moz_gtk_scrollbar_button_paint(cairo_t *cr, GdkRectangle* rect,
+ ensure_scrollbar_widget();
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL)
+- scrollbar = gVertScrollbarWidget;
++ scrollbar = gVertScrollbar.widget;
+ else
+- scrollbar = gHorizScrollbarWidget;
++ scrollbar = gHorizScrollbar.widget;
+
+ gtk_widget_set_direction(scrollbar, direction);
+
+@@ -1175,26 +1373,23 @@ moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
+ GtkTextDirection direction)
+ {
+ GtkStyleContext* style;
+- GtkScrollbar *scrollbar;
+
+ ensure_scrollbar_widget();
+
+- if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
+- scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
+- else
+- scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
+-
+- gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
++ if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL) {
++ gtk_widget_set_direction(GTK_WIDGET(gHorizScrollbar.widget), direction);
++ style = gHorizScrollbar.scroll.styleTrough;
++ }
++ else {
++ gtk_widget_set_direction(GTK_WIDGET(gVertScrollbar.widget), direction);
++ style = gVertScrollbar.scroll.styleTrough;
++ }
+
+ if (flags & MOZ_GTK_TRACK_OPAQUE) {
+ style = gtk_widget_get_style_context(GTK_WIDGET(gProtoWindow));
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ }
+
+- style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar));
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
+-
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+
+@@ -1202,7 +1397,6 @@ moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
+ gtk_render_focus(style, cr,
+ rect->x, rect->y, rect->width, rect->height);
+ }
+- gtk_style_context_restore(style);
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1214,25 +1408,21 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
+ {
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+ GtkStyleContext* style;
+- GtkScrollbar *scrollbar;
+ GtkAdjustment *adj;
+ GtkBorder margin;
+
+ ensure_scrollbar_widget();
+
+- if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
+- scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
+- else
+- scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
++ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
++ style = gHorizScrollbar.scroll.styleSlider;
++ gtk_widget_set_direction(GTK_WIDGET(gHorizScrollbar.widget), direction);
++ }
++ else {
++ style = gVertScrollbar.scroll.styleSlider;
++ gtk_widget_set_direction(GTK_WIDGET(gVertScrollbar.widget), direction);
++ }
+
+- gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+-
+- style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar));
+- gtk_style_context_save(style);
+-
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER);
+ gtk_style_context_set_state(style, state_flags);
+-
+ gtk_style_context_get_margin (style, state_flags, &margin);
+
+ gtk_render_slider(style, cr,
+@@ -1243,8 +1433,6 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
+ (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
+
+- gtk_style_context_restore(style);
+-
+ return MOZ_GTK_SUCCESS;
+ }
+
+@@ -1255,8 +1443,8 @@ moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkStyleContext* style;
+
+ ensure_spin_widget();
+- gtk_widget_set_direction(gSpinWidget, direction);
+- style = gtk_widget_get_style_context(gSpinWidget);
++ gtk_widget_set_direction(gSpin.widget, direction);
++ style = gSpin.spin.style;
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+@@ -1275,11 +1463,10 @@ moz_gtk_spin_updown_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkStyleContext* style;
+
+ ensure_spin_widget();
+- style = gtk_widget_get_style_context(gSpinWidget);
++ style = gSpin.spin.style;
+ gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
+ gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+- gtk_widget_set_direction(gSpinWidget, direction);
++ gtk_widget_set_direction(gSpin.widget, direction);
+
+ gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+ gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+@@ -1445,15 +1632,13 @@ moz_gtk_vpaned_paint(cairo_t *cr, GdkRectangle* rect,
+ static gint
+ moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+- GtkWidget* widget, GtkTextDirection direction)
++ MozGtkWidget* w, GtkTextDirection direction)
+ {
+ gint x = rect->x, y = rect->y, width = rect->width, height = rect->height;
+- GtkStyleContext* style;
+ int draw_focus_outline_only = state->depressed; // NS_THEME_FOCUS_OUTLINE
++ GtkStyleContext* style = w->entry.style;
+
+- gtk_widget_set_direction(widget, direction);
+-
+- style = gtk_widget_get_style_context(widget);
++ gtk_widget_set_direction(w->widget, direction);
+
+ if (draw_focus_outline_only) {
+ // Inflate the given 'rect' with the focus outline size.
+@@ -1473,10 +1658,9 @@ moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
+ * textarea window uses gtk_paint_flat_box when exposed */
+
+ /* This gets us a lovely greyish disabledish look */
+- gtk_widget_set_sensitive(widget, !state->disabled);
++ gtk_widget_set_sensitive(w->widget, !state->disabled);
+
+ gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_ENTRY);
+
+ /* Now paint the shadow and focus border.
+ * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
+@@ -1526,7 +1710,7 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect,
+ style = gtk_widget_get_style_context(gScrolledWindowWidget);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
+- gtk_style_context_get_border(style, state_flags, &border);
++ moz_gtk_get_style_border(style, state_flags, &border);
+ xthickness = border.left;
+ ythickness = border.top;
+
+@@ -1697,7 +1881,7 @@ moz_gtk_combo_box_paint(cairo_t *cr, GdkRectangle* rect,
+ if (direction == GTK_TEXT_DIR_LTR) {
+ GtkBorder padding;
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+- gtk_style_context_get_padding(style, state_flags, &padding);
++ moz_gtk_get_style_padding(style, state_flags, &padding);
+ arrow_rect.x -= padding.left;
+ }
+ else
+@@ -1799,29 +1983,27 @@ moz_gtk_container_paint(cairo_t *cr, GdkRectangle* rect,
+ gboolean isradio, GtkTextDirection direction)
+ {
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+- GtkStyleContext* style;
+- GtkWidget *widget;
++ MozGtkWidget *widget;
+
+ if (isradio) {
+ ensure_radiobutton_widget();
+- widget = gRadiobuttonWidget;
++ widget = &gRadiobutton;
+ } else {
+ ensure_checkbox_widget();
+- widget = gCheckboxWidget;
++ widget = &gCheckbox;
+ }
+- gtk_widget_set_direction(widget, direction);
++ gtk_widget_set_direction(widget->widget, direction);
+
+- style = gtk_widget_get_style_context(widget);
+- gtk_style_context_save(style);
+- gtk_style_context_set_state(style, state_flags);
++ gtk_style_context_save(widget->check.style);
++ gtk_style_context_set_state(widget->check.style, state_flags);
+
+ /* this is for drawing a prelight box */
+ if (state_flags & GTK_STATE_FLAG_PRELIGHT) {
+- gtk_render_background(style, cr,
++ gtk_render_background(widget->check.style, cr,
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+- gtk_style_context_restore(style);
++ gtk_style_context_restore(widget->check.style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1831,32 +2013,26 @@ moz_gtk_toggle_label_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ gboolean isradio, GtkTextDirection direction)
+ {
+- GtkStyleContext *style;
+- GtkWidget *widget;
++ MozGtkWidget *widget;
+
+ if (!state->focused)
+ return MOZ_GTK_SUCCESS;
+
+ if (isradio) {
+ ensure_radiobutton_widget();
+- widget = gRadiobuttonWidget;
++ widget = &gRadiobutton;
+ } else {
+ ensure_checkbox_widget();
+- widget = gCheckboxWidget;
++ widget = &gCheckbox;
+ }
+- style = gtk_widget_get_style_context(widget);
+- gtk_style_context_save(style);
+- if (isradio) {
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
+- } else {
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
+- }
+- gtk_widget_set_direction(widget, direction);
++ gtk_style_context_save(widget->check.styleLabel);
++ gtk_widget_set_direction(widget->widget, direction);
+
+- gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
+- gtk_render_focus(style, cr,
++ gtk_style_context_set_state(widget->check.styleLabel,
++ GetStateFlagsFromGtkWidgetState(state));
++ gtk_render_focus(widget->check.styleLabel, cr,
+ rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
++ gtk_style_context_restore(widget->check.styleLabel);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -1917,7 +2093,7 @@ moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect,
+ rect->height * (end_fraction - start_fraction));
+ } else {
+ GtkBorder padding;
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+
+ paint_width = padding.left;
+ if (paint_width > rect->width)
+@@ -2004,18 +2180,13 @@ static gint
+ moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+ {
+- GtkStyleContext* style;
+-
+ ensure_progress_widget();
+- gtk_widget_set_direction(gProgressWidget, direction);
++ gtk_widget_set_direction(gProgressBar.widget, direction);
+
+- style = gtk_widget_get_style_context(gProgressWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
+-
+- gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_style_context_restore(style);
++ gtk_render_background(gProgressBar.progress.styleTrough, cr,
++ rect->x, rect->y, rect->width, rect->height);
++ gtk_render_frame(gProgressBar.progress.styleTrough, cr,
++ rect->x, rect->y, rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -2025,15 +2196,8 @@ moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction,
+ GtkThemeWidgetType widget)
+ {
+- GtkStyleContext* style;
+-
+ ensure_progress_widget();
+- gtk_widget_set_direction(gProgressWidget, direction);
+-
+- style = gtk_widget_get_style_context(gProgressWidget);
+- gtk_style_context_save(style);
+- gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR);
++ gtk_widget_set_direction(gProgressBar.widget, direction);
+
+ if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
+ widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
+@@ -2072,12 +2236,14 @@ moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect,
+ // gtk_render_activity was used to render progress chunks on GTK versions
+ // before 3.13.7, see bug 1173907.
+ if (!gtk_check_version(3, 13, 7)) {
+- gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
+- gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
++ gtk_render_background(gProgressBar.progress.styleProgress, cr,
++ rect->x, rect->y, rect->width, rect->height);
++ gtk_render_frame(gProgressBar.progress.styleProgress, cr,
++ rect->x, rect->y, rect->width, rect->height);
+ } else {
+- gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height);
++ gtk_render_activity(gProgressBar.progress.styleProgress, cr,
++ rect->x, rect->y, rect->width, rect->height);
+ }
+- gtk_style_context_restore(style);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -2094,7 +2260,7 @@ moz_gtk_get_tab_thickness(void)
+
+ style = gtk_widget_get_style_context(gTabWidget);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK);
+- gtk_style_context_get_border(style, 0, &border);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
+
+ if (border.top < 2)
+ return 2; /* some themes don't set ythickness correctly */
+@@ -2290,7 +2456,7 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectangle* rect,
+ gtk_style_context_save(style);
+ moz_gtk_tab_prepare_style_context(style, flags);
+
+- gtk_style_context_get_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
++ moz_gtk_get_style_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
+
+ focusRect.x += padding.left;
+ focusRect.width -= (padding.left + padding.right);
+@@ -2406,7 +2572,7 @@ moz_gtk_tab_scroll_arrow_paint(cairo_t *cr, GdkRectangle* rect,
+ }
+
+ static gint
+-moz_gtk_menu_bar_paint(cairo_t *cr, GdkRectangle* rect,
++moz_gtk_menu_bar_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state,
+ GtkTextDirection direction)
+ {
+ GtkStyleContext* style;
+@@ -2467,7 +2633,7 @@ moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect,
+ border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget));
+
+ style = gtk_widget_get_style_context(gMenuSeparatorWidget);
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+
+ x = rect->x + border_width;
+ y = rect->y + border_width;
+@@ -2521,7 +2687,8 @@ moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
+ item_widget = gMenuItemWidget;
+ }
+ style = gtk_widget_get_style_context(item_widget);
+- gtk_style_context_save(style);
++// TODO - FIX!
++// gtk_style_context_save(style);
+
+ if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
+@@ -2540,7 +2707,7 @@ moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
+
+ gtk_render_background(style, cr, x, y, w, h);
+ gtk_render_frame(style, cr, x, y, w, h);
+- gtk_style_context_restore(style);
++// gtk_style_context_restore(style);
+ }
+
+ return MOZ_GTK_SUCCESS;
+@@ -2556,7 +2723,10 @@ moz_gtk_menu_arrow_paint(cairo_t *cr, GdkRectangle* rect,
+
+ ensure_menu_item_widget();
+ gtk_widget_set_direction(gMenuItemWidget, direction);
+-
++/*
++ state_flags |= (direction == GTK_TEXT_DIR_LTR) ? GTK_STATE_FLAG_DIR_LTR :
++ GTK_STATE_FLAG_DIR_RTL;
++*/
+ style = gtk_widget_get_style_context(gMenuItemWidget);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
+@@ -2606,7 +2776,7 @@ moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
+ }
+
+ gtk_style_context_set_state(style, state_flags);
+- gtk_style_context_get_padding(style, state_flags, &padding);
++ moz_gtk_get_style_padding(style, state_flags, &padding);
+
+ offset = gtk_container_get_border_width(GTK_CONTAINER(gCheckMenuItemWidget)) +
+ padding.left + 2;
+@@ -2658,7 +2828,7 @@ moz_gtk_add_style_border(GtkStyleContext* style,
+ {
+ GtkBorder border;
+
+- gtk_style_context_get_border(style, 0, &border);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
+
+ *left += border.left;
+ *right += border.right;
+@@ -2667,12 +2837,22 @@ moz_gtk_add_style_border(GtkStyleContext* style,
+ }
+
+ static void
++moz_gtk_get_style_border(GtkStyleContext* style, GtkStateFlags state_flags,
++ GtkBorder *border)
++{
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, state_flags);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), border);
++ gtk_style_context_restore(style);
++}
++
++static void
+ moz_gtk_add_style_padding(GtkStyleContext* style,
+ gint* left, gint* top, gint* right, gint* bottom)
+ {
+ GtkBorder padding;
+
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+
+ *left += padding.left;
+ *right += padding.right;
+@@ -2680,6 +2860,16 @@ moz_gtk_add_style_padding(GtkStyleContext* style,
+ *bottom += padding.bottom;
+ }
+
++static void
++moz_gtk_get_style_padding(GtkStyleContext* style, GtkStateFlags state_flags,
++ GtkBorder *padding)
++{
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, state_flags);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), padding);
++ gtk_style_context_restore(style);
++}
++
+ gint
+ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ gint* right, gint* bottom, GtkTextDirection direction,
+@@ -2694,36 +2884,27 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ case MOZ_GTK_TOOLBAR_BUTTON:
+ {
+ ensure_button_widget();
+- style = gtk_widget_get_style_context(gButtonWidget);
+
+- *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
+-
+- if (widget == MOZ_GTK_TOOLBAR_BUTTON) {
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, "image-button");
+- }
+-
+- moz_gtk_add_style_padding(style, left, top, right, bottom);
+-
+- if (widget == MOZ_GTK_TOOLBAR_BUTTON)
+- gtk_style_context_restore(style);
++ *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButton.widget));
++ moz_gtk_add_style_padding(gButton.button.style, left, top, right, bottom);
+
+ // XXX: Subtract 1 pixel from the border to account for the added
+ // -moz-focus-inner border (Bug 1228281).
+ *left -= 1; *top -= 1; *right -= 1; *bottom -= 1;
+- moz_gtk_add_style_border(style, left, top, right, bottom);
++ moz_gtk_add_style_border(gButton.button.style, left, top, right, bottom);
++
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_ENTRY:
+ {
+ ensure_entry_widget();
+- style = gtk_widget_get_style_context(gEntryWidget);
+
+ // XXX: Subtract 1 pixel from the padding to account for the default
+ // padding in forms.css. See bug 1187385.
+ *left = *top = *right = *bottom = -1;
+- moz_gtk_add_style_padding(style, left, top, right, bottom);
+- moz_gtk_add_style_border(style, left, top, right, bottom);
++
++ moz_gtk_add_style_padding(gEntry.entry.style, left, top, right, bottom);
++ moz_gtk_add_style_border(gEntry.entry.style, left, top, right, bottom);
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -2759,7 +2940,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ break;
+ case MOZ_GTK_DROPDOWN_ENTRY:
+ ensure_combo_box_entry_widgets();
+- w = gComboBoxEntryTextareaWidget;
++ w = gComboBoxEntryTextarea.widget;
+ break;
+ case MOZ_GTK_DROPDOWN_ARROW:
+ ensure_combo_box_entry_widgets();
+@@ -2795,7 +2976,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+
+ if (!wide_separators) {
+ style = gtk_widget_get_style_context(gComboBoxSeparatorWidget);
+- gtk_style_context_get_border(style, 0, &border);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
+ separator_width = border.left;
+ }
+ }
+@@ -2814,14 +2995,17 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ w = gTabWidget;
+ break;
+ case MOZ_GTK_PROGRESSBAR:
+- ensure_progress_widget();
+- w = gProgressWidget;
+- break;
++ {
++ ensure_progress_widget();
++ moz_gtk_add_style_border(gProgressBar.progress.styleTrough,
++ left, top, right, bottom);
++ return MOZ_GTK_SUCCESS;
++ }
+ case MOZ_GTK_SPINBUTTON_ENTRY:
+ case MOZ_GTK_SPINBUTTON_UP:
+ case MOZ_GTK_SPINBUTTON_DOWN:
+ ensure_spin_widget();
+- w = gSpinWidget;
++ w = gSpin.widget;
+ break;
+ case MOZ_GTK_SCALE_HORIZONTAL:
+ ensure_scale_widget();
+@@ -2840,12 +3024,13 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ {
+ if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
+ ensure_checkbox_widget();
+- w = gCheckboxWidget;
++ w = gCheckbox.widget;
++ style = gCheckbox.check.styleCheck;
+ } else {
+ ensure_radiobutton_widget();
+- w = gRadiobuttonWidget;
++ w = gRadiobutton.widget;
++ style = gRadiobutton.check.styleCheck;
+ }
+- style = gtk_widget_get_style_context(w);
+
+ *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
+ moz_gtk_add_style_border(style,
+@@ -2978,6 +3163,32 @@ moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
+ }
+
+ gint
++moz_gtk_get_entry_height(gint* height)
++{
++ GtkRequisition requisition;
++ ensure_entry_widget();
++
++ gtk_widget_get_preferred_size(gEntry.widget, NULL, &requisition);
++ *height = requisition.height;
++
++ return MOZ_GTK_SUCCESS;
++}
++
++
++gint
++moz_gtk_get_button_height(gint* height)
++{
++ GtkRequisition requisition;
++ ensure_entry_widget();
++
++ gtk_widget_get_preferred_size(gButton.widget, NULL, &requisition);
++ *height = requisition.height;
++
++ return MOZ_GTK_SUCCESS;
++}
++
++
++gint
+ moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
+ {
+ gint arrow_size;
+@@ -3022,7 +3233,7 @@ moz_gtk_get_toolbar_separator_width(gint* size)
+ "separator-width", &separator_width,
+ NULL);
+ /* Just in case... */
+- gtk_style_context_get_border(style, 0, &border);
++ gtk_style_context_get_border(style, gtk_style_context_get_state(style), &border);
+ *size = MAX(*size, (wide_separators ? separator_width : border.left));
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -3064,7 +3275,7 @@ moz_gtk_get_menu_separator_height(gint *size)
+ border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget));
+
+ style = gtk_widget_get_style_context(gMenuSeparatorWidget);
+- gtk_style_context_get_padding(style, 0, &padding);
++ gtk_style_context_get_padding(style, gtk_style_context_get_state(style), &padding);
+
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_SEPARATOR);
+@@ -3122,15 +3333,21 @@ moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
+ {
+ ensure_scrollbar_widget();
+
+- gtk_widget_style_get (gHorizScrollbarWidget,
++ gtk_widget_style_get (gHorizScrollbar.widget,
+ "slider_width", &metrics->slider_width,
+ "trough_border", &metrics->trough_border,
+ "stepper_size", &metrics->stepper_size,
+ "stepper_spacing", &metrics->stepper_spacing,
+ NULL);
+
+- metrics->min_slider_size =
+- gtk_range_get_min_slider_size(GTK_RANGE(gHorizScrollbarWidget));
++ if (!gtk_check_version(3,19,7)) {
++ gtk_style_context_get(gVertScrollbar.scroll.styleSlider,
++ gtk_style_context_get_state(gVertScrollbar.scroll.styleSlider),
++ "min-height", &metrics->min_slider_size, NULL);
++ } else {
++ metrics->min_slider_size =
++ gtk_range_get_min_slider_size(GTK_RANGE(gVertScrollbar.widget));
++ }
+
+ return MOZ_GTK_SUCCESS;
+ }
+@@ -3155,7 +3372,7 @@ moz_gtk_images_in_buttons()
+ GtkSettings* settings;
+
+ ensure_button_widget();
+- settings = gtk_widget_get_settings(gButtonWidget);
++ settings = gtk_widget_get_settings(gButton.widget);
+
+ g_object_get(settings, "gtk-button-images", &result, NULL);
+ return result;
+@@ -3183,7 +3400,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
+ }
+ ensure_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+- (GtkReliefStyle) flags, gButtonWidget,
++ (GtkReliefStyle) flags, gButton.widget,
+ direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+@@ -3233,7 +3450,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
+ case MOZ_GTK_SPINBUTTON_ENTRY:
+ ensure_spin_widget();
+ return moz_gtk_entry_paint(cr, rect, state,
+- gSpinWidget, direction);
++ &gSpin, direction);
+ break;
+ case MOZ_GTK_GRIPPER:
+ return moz_gtk_gripper_paint(cr, rect, state,
+@@ -3260,7 +3477,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ return moz_gtk_entry_paint(cr, rect, state,
+- gEntryWidget, direction);
++ &gEntry, direction);
+ break;
+ case MOZ_GTK_DROPDOWN:
+ return moz_gtk_combo_box_paint(cr, rect, state, direction);
+@@ -3272,7 +3489,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
+ case MOZ_GTK_DROPDOWN_ENTRY:
+ ensure_combo_box_entry_widgets();
+ return moz_gtk_entry_paint(cr, rect, state,
+- gComboBoxEntryTextareaWidget, direction);
++ &gComboBoxEntryTextarea, direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON_CONTAINER:
+ case MOZ_GTK_RADIOBUTTON_CONTAINER:
+@@ -3324,7 +3541,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
+ (GtkArrowType) flags, direction);
+ break;
+ case MOZ_GTK_MENUBAR:
+- return moz_gtk_menu_bar_paint(cr, rect, direction);
++ return moz_gtk_menu_bar_paint(cr, rect, state, direction);
+ break;
+ case MOZ_GTK_MENUPOPUP:
+ return moz_gtk_menu_popup_paint(cr, rect, direction);
+@@ -3375,7 +3592,7 @@ GtkWidget* moz_gtk_get_scrollbar_widget(void)
+ {
+ MOZ_ASSERT(is_initialized, "Forgot to call moz_gtk_init()");
+ ensure_scrollbar_widget();
+- return gHorizScrollbarWidget;
++ return gVertScrollbar.widget;
+ }
+
+ gboolean moz_gtk_has_scrollbar_buttons(void)
+@@ -3383,7 +3600,7 @@ gboolean moz_gtk_has_scrollbar_buttons(void)
+ gboolean backward, forward, secondary_backward, secondary_forward;
+ MOZ_ASSERT(is_initialized, "Forgot to call moz_gtk_init()");
+ ensure_scrollbar_widget();
+- gtk_widget_style_get (gHorizScrollbarWidget,
++ gtk_widget_style_get (gHorizScrollbar.widget,
+ "has-backward-stepper", &backward,
+ "has-forward-stepper", &forward,
+ "has-secondary-backward-stepper", &secondary_backward,
+@@ -3409,17 +3626,19 @@ moz_gtk_shutdown()
+
+ gProtoWindow = NULL;
+ gProtoLayout = NULL;
+- gButtonWidget = NULL;
++
++ // MozWidgets
++ moz_gtk_widget_free(&gButton);
+ gToggleButtonWidget = NULL;
+ gButtonArrowWidget = NULL;
+- gCheckboxWidget = NULL;
+- gRadiobuttonWidget = NULL;
+- gHorizScrollbarWidget = NULL;
+- gVertScrollbarWidget = NULL;
+- gSpinWidget = NULL;
++ moz_gtk_widget_free(&gCheckbox);
++ moz_gtk_widget_free(&gRadiobutton);
++ moz_gtk_widget_free(&gHorizScrollbar);
++ moz_gtk_widget_free(&gVertScrollbar);
++ moz_gtk_widget_free(&gSpin);
+ gHScaleWidget = NULL;
+ gVScaleWidget = NULL;
+- gEntryWidget = NULL;
++ moz_gtk_widget_free(&gEntry);
+ gComboBoxWidget = NULL;
+ gComboBoxButtonWidget = NULL;
+ gComboBoxSeparatorWidget = NULL;
+@@ -3427,12 +3646,12 @@ moz_gtk_shutdown()
+ gComboBoxEntryWidget = NULL;
+ gComboBoxEntryButtonWidget = NULL;
+ gComboBoxEntryArrowWidget = NULL;
+- gComboBoxEntryTextareaWidget = NULL;
++ moz_gtk_widget_free(&gComboBoxEntryTextarea);
+ gHandleBoxWidget = NULL;
+ gToolbarWidget = NULL;
+ gStatusbarWidget = NULL;
+ gFrameWidget = NULL;
+- gProgressWidget = NULL;
++ moz_gtk_widget_free(&gProgressBar);
+ gTabWidget = NULL;
+ gTooltipWidget = NULL;
+ gMenuBarWidget = NULL;
+diff --git c/widget/gtk/gtkdrawing.h i/widget/gtk/gtkdrawing.h
+index 9e5c38d..7aa7af0 100644
+--- c/widget/gtk/gtkdrawing.h
++++ i/widget/gtk/gtkdrawing.h
+@@ -67,6 +67,13 @@ typedef enum {
+ MOZ_GTK_TAB_SELECTED = 1 << 10
+ } GtkTabFlags;
+
++typedef struct {
++ GType type;
++ const gchar *name;
++ const gchar *class1;
++ const gchar *class2;
++} GtkCssNode;
++
+ /** flags for menuitems **/
+ typedef enum {
+ /* menuitem is part of the menubar */
+@@ -394,6 +401,10 @@ gint moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height);
+ */
+ gint moz_gtk_get_arrow_size(gint* width, gint* height);
+
++gint moz_gtk_get_entry_height(gint* height);
++
++gint moz_gtk_get_button_height(gint* height);
++
+ /**
+ * Get the desired size of a toolbar separator
+ * size: [OUT] the desired width
+@@ -464,6 +475,12 @@ gboolean moz_gtk_images_in_buttons(void);
+ */
+ gboolean moz_gtk_has_scrollbar_buttons(void);
+
++
++GtkStyleContext *
++moz_gtk_style_create(GtkCssNode *node, GtkStyleContext *parent);
++
++
++
+ #ifdef __cplusplus
+ }
+ #endif /* __cplusplus */
+diff --git c/widget/gtk/mozgtk/mozgtk.c i/widget/gtk/mozgtk/mozgtk.c
+index 0bb4dfd..2a9ff1a 100644
+--- c/widget/gtk/mozgtk/mozgtk.c
++++ i/widget/gtk/mozgtk/mozgtk.c
+@@ -502,6 +502,11 @@ STUB(gtk_window_set_type_hint)
+ STUB(gtk_window_set_wmclass)
+ STUB(gtk_window_unfullscreen)
+ STUB(gtk_window_unmaximize)
++STUB(gtk_widget_get_preferred_height_and_baseline_for_width)
++STUB(gtk_entry_get_text_area)
++STUB(gtk_check_menu_item_get_type)
++STUB(gtk_spin_button_get_type)
++STUB(gtk_button_get_type)
+ #endif
+
+ #ifdef GTK3_SYMBOLS
+@@ -549,6 +554,7 @@ STUB(gtk_style_context_get_border_color)
+ STUB(gtk_style_context_get_color)
+ STUB(gtk_style_context_get_margin)
+ STUB(gtk_style_context_get_padding)
++STUB(gtk_style_context_get_state)
+ STUB(gtk_style_context_has_class)
+ STUB(gtk_style_context_new)
+ STUB(gtk_style_context_remove_class)
+@@ -576,6 +582,13 @@ STUB(gtk_color_chooser_get_type)
+ STUB(gtk_color_chooser_set_rgba)
+ STUB(gtk_color_chooser_get_rgba)
+ STUB(gtk_color_chooser_set_use_alpha)
++STUB(gtk_style_context_get_path)
++STUB(gtk_widget_path_copy)
++STUB(gtk_widget_path_iter_set_object_name)
++STUB(gtk_widget_path_iter_add_class)
++STUB(gtk_widget_path_iter_get_state)
++STUB(gtk_style_context_set_parent)
++STUB(gtk_widget_path_unref)
+ #endif
+
+ #ifdef GTK2_SYMBOLS
+diff --git c/widget/gtk/nsLookAndFeel.cpp i/widget/gtk/nsLookAndFeel.cpp
+index 52edfb2..fc0c585a 100644
+--- c/widget/gtk/nsLookAndFeel.cpp
++++ i/widget/gtk/nsLookAndFeel.cpp
+@@ -232,14 +232,18 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
+ case eColorID_activeborder:
+ // active window border
+ gtk_style_context_get_border_color(mBackgroundStyle,
+- GTK_STATE_FLAG_NORMAL, &gdk_color);
++ gtk_style_context_get_state(mBackgroundStyle),
++ &gdk_color);
+ aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+ break;
+ case eColorID_inactiveborder:
+ // inactive window border
++ gtk_style_context_save(mBackgroundStyle);
++ gtk_style_context_set_state(mBackgroundStyle, GTK_STATE_FLAG_INSENSITIVE);
+ gtk_style_context_get_border_color(mBackgroundStyle,
+- GTK_STATE_FLAG_INSENSITIVE,
++ gtk_style_context_get_state(mBackgroundStyle),
+ &gdk_color);
++ gtk_style_context_restore(mBackgroundStyle);
+ aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+ break;
+ case eColorID_graytext: // disabled text in windows, menus, etc.
+@@ -248,9 +252,12 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
+ break;
+ case eColorID_inactivecaption:
+ // inactive window caption
++ gtk_style_context_save(mBackgroundStyle);
++ gtk_style_context_set_state(mBackgroundStyle, GTK_STATE_FLAG_INSENSITIVE);
+ gtk_style_context_get_background_color(mBackgroundStyle,
+- GTK_STATE_FLAG_INSENSITIVE,
++ gtk_style_context_get_state(mBackgroundStyle),
+ &gdk_color);
++ gtk_style_context_restore(mBackgroundStyle);
+ aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+ break;
+ #endif
+@@ -376,13 +383,17 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
+ case eColorID__moz_buttondefault:
+ // default button border color
+ gtk_style_context_get_border_color(mButtonStyle,
+- GTK_STATE_FLAG_NORMAL, &gdk_color);
++ gtk_style_context_get_state(mButtonStyle),
++ &gdk_color);
+ aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+ break;
+ case eColorID__moz_buttonhoverface:
++ gtk_style_context_save(mButtonStyle);
++ gtk_style_context_set_state(mButtonStyle, GTK_STATE_FLAG_PRELIGHT);
+ gtk_style_context_get_background_color(mButtonStyle,
+- GTK_STATE_FLAG_PRELIGHT,
++ gtk_style_context_get_state(mButtonStyle),
+ &gdk_color);
++ gtk_style_context_restore(mButtonStyle);
+ aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
+ break;
+ case eColorID__moz_buttonhovertext:
+@@ -989,7 +1000,7 @@ nsLookAndFeel::Init()
+ style = create_context(path);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sMozScrollbar = GDK_RGBA_TO_NS_RGBA(color);
+ g_object_unref(style);
+
+@@ -997,18 +1008,18 @@ nsLookAndFeel::Init()
+ style = create_context(path);
+ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sMozWindowBackground = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMozWindowText = GDK_RGBA_TO_NS_RGBA(color);
+ gtk_style_context_restore(style);
+
+ // tooltip foreground and background
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sInfoBackground = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sInfoText = GDK_RGBA_TO_NS_RGBA(color);
+ g_object_unref(style);
+
+@@ -1023,20 +1034,26 @@ nsLookAndFeel::Init()
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+
+ style = gtk_widget_get_style_context(accel_label);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMenuText = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_INSENSITIVE, &color);
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, GTK_STATE_FLAG_INSENSITIVE);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color);
++ gtk_style_context_restore(style);
+
+ style = gtk_widget_get_style_context(menu);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sMenuBackground = GDK_RGBA_TO_NS_RGBA(color);
+
+ style = gtk_widget_get_style_context(menuitem);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, GTK_STATE_FLAG_PRELIGHT);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sMenuHover = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMenuHoverText = GDK_RGBA_TO_NS_RGBA(color);
++ gtk_style_context_restore(style);
+
+ g_object_unref(menu);
+ #endif
+@@ -1145,44 +1162,54 @@ nsLookAndFeel::Init()
+ GDK_COLOR_TO_NS_RGB(style->dark[GTK_STATE_NORMAL]);
+ }
+ #else
++ GtkCssNode labelPath[] = {
++ { GTK_TYPE_LABEL, "label", "view", NULL },
++ { G_TYPE_NONE, "selection", NULL, NULL }
++ };
++
++ GtkStyleContext *styleLabel;
++ GtkStyleContext *styleSelection;
++ GtkBorder padding;
++
+ // Text colors
+- style = gtk_widget_get_style_context(textView);
+- gtk_style_context_save(style);
+- gtk_style_context_add_class(style, GTK_STYLE_CLASS_VIEW);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ styleLabel = moz_gtk_style_create(labelPath, NULL);
++ styleSelection = moz_gtk_style_create(labelPath+1, styleLabel);
++
++ gtk_style_context_get_background_color(styleLabel, gtk_style_context_get_state(styleLabel), &color);
+ sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(styleLabel, gtk_style_context_get_state(styleLabel), &color);
+ sMozFieldText = GDK_RGBA_TO_NS_RGBA(color);
+
+ // Selected text and background
+- gtk_style_context_get_background_color(style,
+- static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED),
+- &color);
++ gtk_style_context_get_background_color(styleSelection, gtk_style_context_get_state(styleSelection), &color);
+ sTextSelectedBackground = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style,
+- static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED),
+- &color);
++ gtk_style_context_get_color(styleSelection, gtk_style_context_get_state(styleSelection), &color);
+ sTextSelectedText = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_restore(style);
+
+ // Button text, background, border
+ style = gtk_widget_get_style_context(label);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sButtonText = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, GTK_STATE_FLAG_PRELIGHT);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color);
++ gtk_style_context_restore(style);
+
+ // Combobox text color
+ style = gtk_widget_get_style_context(comboboxLabel);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sComboBoxText = GDK_RGBA_TO_NS_RGBA(color);
+
+ // Menubar text and hover text colors
+ style = gtk_widget_get_style_context(menuBar);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMenuBarText = GDK_RGBA_TO_NS_RGBA(color);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
++ gtk_style_context_save(style);
++ gtk_style_context_set_state(style, GTK_STATE_FLAG_PRELIGHT);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sMenuBarHoverText = GDK_RGBA_TO_NS_RGBA(color);
++ gtk_style_context_restore(style);
+
+ // GTK's guide to fancy odd row background colors:
+ // 1) Check if a theme explicitly defines an odd row color
+@@ -1195,7 +1222,7 @@ nsLookAndFeel::Init()
+ // Get odd row background color
+ gtk_style_context_save(style);
+ gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD);
+- gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_background_color(style, gtk_style_context_get_state(style), &color);
+ sOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
+ gtk_style_context_restore(style);
+
+@@ -1205,7 +1232,7 @@ nsLookAndFeel::Init()
+ // TODO GTK3 - update sFrameOuterLightBorder
+ // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles (Bug 978172).
+ style = gtk_widget_get_style_context(frame);
+- gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_border_color(style, gtk_style_context_get_state(style), &color);
+ sFrameInnerDarkBorder = sFrameOuterLightBorder = GDK_RGBA_TO_NS_RGBA(color);
+
+ gtk_widget_path_free(path);
+@@ -1217,9 +1244,11 @@ nsLookAndFeel::Init()
+ gtk_container_add(GTK_CONTAINER(parent), infoBar);
+ gtk_container_add(GTK_CONTAINER(infoBarContent), infoBarLabel);
+ style = gtk_widget_get_style_context(infoBarLabel);
++ gtk_style_context_save(style);
+ gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO);
+- gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
++ gtk_style_context_get_color(style, gtk_style_context_get_state(style), &color);
+ sInfoBarText = GDK_RGBA_TO_NS_RGBA(color);
++ gtk_style_context_restore(style);
+ #endif
+ // Some themes have a unified menu bar, and support window dragging on it
+ gboolean supports_menubar_drag = FALSE;
+diff --git c/widget/gtk/nsNativeThemeGTK.cpp i/widget/gtk/nsNativeThemeGTK.cpp
+index fd5a67d..5bc8fa1 100644
+--- c/widget/gtk/nsNativeThemeGTK.cpp
++++ i/widget/gtk/nsNativeThemeGTK.cpp
+@@ -1548,9 +1548,6 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
+ case NS_THEME_RADIO_CONTAINER:
+ case NS_THEME_CHECKBOX_LABEL:
+ case NS_THEME_RADIO_LABEL:
+- case NS_THEME_BUTTON:
+- case NS_THEME_DROPDOWN:
+- case NS_THEME_TOOLBAR_BUTTON:
+ case NS_THEME_TREEVIEW_HEADER_CELL:
+ {
+ // Just include our border, and let the box code augment the size.
+@@ -1561,6 +1558,21 @@ nsNativeThemeGTK::GetMinimumWidgetSize(nsPresContext* aPresContext,
+ aResult->height = border.top + border.bottom;
+ }
+ break;
++ case NS_THEME_BUTTON:
++ case NS_THEME_DROPDOWN:
++ case NS_THEME_TOOLBAR_BUTTON:
++ {
++ moz_gtk_get_button_height(&aResult->height);
++ }
++ break;
++ case NS_THEME_FOCUS_OUTLINE:
++ case NS_THEME_NUMBER_INPUT:
++ case NS_THEME_TEXTFIELD:
++ case NS_THEME_TEXTFIELD_MULTILINE:
++ {
++ moz_gtk_get_entry_height(&aResult->height);
++ }
++ break;
+ case NS_THEME_TOOLBAR_SEPARATOR:
+ {
+ gint separator_width;
diff --git a/libre/icecat/icecat-install-dir.patch b/libre/icecat/icecat-install-dir.patch
new file mode 100644
index 000000000..e15bf0b68
--- /dev/null
+++ b/libre/icecat/icecat-install-dir.patch
@@ -0,0 +1,12 @@
+diff -Nur a/config/baseconfig.mk c/config/baseconfig.mk
+--- a/config/baseconfig.mk 2014-10-09 12:52:39.000000000 -0200
++++ b/config/baseconfig.mk 2014-10-21 18:34:35.803894661 -0200
+@@ -4,7 +4,7 @@
+ # whether a normal build is happening or whether the check is running.
+ includedir := $(includedir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
+ idldir = $(datadir)/idl/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
+-installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
++installdir = $(libdir)/$(MOZ_APP_NAME)
+ sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
+ ifndef TOP_DIST
+ TOP_DIST = dist
diff --git a/libre/icecat/icecat.desktop b/libre/icecat/icecat.desktop
new file mode 100644
index 000000000..d2c0ccb03
--- /dev/null
+++ b/libre/icecat/icecat.desktop
@@ -0,0 +1,352 @@
+[Desktop Entry]
+Name=GNU IceCat
+GenericName=Web Browser
+GenericName[ar]=متصفح ويب
+GenericName[ast]=Restolador Web
+GenericName[bn]=ওয়েব ব্রাউজার
+GenericName[ca]=Navegador web
+GenericName[cs]=Webový prohlížeč
+GenericName[da]=Webbrowser
+GenericName[el]=Περιηγητής διαδικτύου
+GenericName[es]=Navegador web
+GenericName[et]=Veebibrauser
+GenericName[fa]=مرورگر اینترنتی
+GenericName[fi]=WWW-selain
+GenericName[fr]=Navigateur Web
+GenericName[gl]=Navegador Web
+GenericName[he]=דפדפן אינטרנט
+GenericName[hr]=Web preglednik
+GenericName[hu]=Webböngésző
+GenericName[it]=Browser web
+GenericName[ja]=ウェブ・ブラウザ
+GenericName[ko]=웹 브라우저
+GenericName[ku]=Geroka torê
+GenericName[lt]=Interneto naršyklė
+GenericName[nb]=Nettleser
+GenericName[nl]=Webbrowser
+GenericName[nn]=Nettlesar
+GenericName[no]=Nettleser
+GenericName[pl]=Przeglądarka WWW
+GenericName[pt]=Navegador Web
+GenericName[pt_BR]=Navegador Web
+GenericName[ro]=Navigator Internet
+GenericName[ru]=Веб-браузер
+GenericName[sk]=Internetový prehliadač
+GenericName[sl]=Spletni brskalnik
+GenericName[sv]=Webbläsare
+GenericName[tr]=Web Tarayıcı
+GenericName[ug]=توركۆرگۈ
+GenericName[uk]=Веб-браузер
+GenericName[vi]=Trình duyệt Web
+GenericName[zh_CN]=网络浏览器
+GenericName[zh_TW]=網路瀏覽器
+Comment=Browse the World Wide Web
+Comment[ar]=تصفح الشبكة العنكبوتية العالمية
+Comment[ast]=Restola pela Rede
+Comment[bn]=ইন্টারনেট ব্রাউজ করুন
+Comment[ca]=Navegueu per la web
+Comment[cs]=Prohlížení stránek World Wide Webu
+Comment[da]=Surf på internettet
+Comment[de]=Im Internet surfen
+Comment[el]=Μπορείτε να περιηγηθείτε στο διαδίκτυο (Web)
+Comment[es]=Navegue por la web
+Comment[et]=Lehitse veebi
+Comment[fa]=صفحات شبکه جهانی اینترنت را مرور نمایید
+Comment[fi]=Selaa Internetin WWW-sivuja
+Comment[fr]=Naviguer sur le Web
+Comment[gl]=Navegar pola rede
+Comment[he]=גלישה ברחבי האינטרנט
+Comment[hr]=Pretražite web
+Comment[hu]=A világháló böngészése
+Comment[it]=Esplora il web
+Comment[ja]=ウェブを閲覧します
+Comment[ko]=웹을 돌아 다닙니다
+Comment[ku]=Li torê bigere
+Comment[lt]=Naršykite internete
+Comment[nb]=Surf på nettet
+Comment[nl]=Verken het internet
+Comment[nn]=Surf på nettet
+Comment[no]=Surf på nettet
+Comment[pl]=Przeglądanie stron WWW
+Comment[pt]=Navegue na Internet
+Comment[pt_BR]=Navegue na Internet
+Comment[ro]=Navigați pe Internet
+Comment[ru]=Доступ в Интернет
+Comment[sk]=Prehliadanie internetu
+Comment[sl]=Brskajte po spletu
+Comment[sv]=Surfa på webben
+Comment[tr]=İnternet'te Gezinin
+Comment[ug]=دۇنيادىكى توربەتلەرنى كۆرگىلى بولىدۇ
+Comment[uk]=Перегляд сторінок Інтернету
+Comment[vi]=Để duyệt các trang web
+Comment[zh_CN]=浏览互联网
+Comment[zh_TW]=瀏覽網際網路
+Exec=icecat %u
+Terminal=false
+Type=Application
+Icon=icecat
+Categories=Network;WebBrowser;
+MimeType=text/html;text/xml;application/xhtml+xml;application/vnd.mozilla.xul+xml;text/mml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;
+StartupNotify=true
+Actions=NewTab;NewWindow;NewPrivateWindow;
+
+[Desktop Action NewTab]
+Name=Open new tab
+Name[ach]=Yab dirica matidi manyen
+Name[af]=Open nuwe oortjie
+Name[an]=Ubrir una pestanya nueva
+Name[ar]=افتح لسانًا جديدًا
+Name[as]=নতুন টেব খোলক
+Name[ast]=Abrir llingüeta nueva
+Name[az]=Yeni vərəq aç
+Name[be]=Адкрыць новую ўстаўку
+Name[bg]=Отваряне на нов подпрозорец
+Name[bn_BD]=নতুন ট্যাব খুলুন
+Name[bn_IN]=নতুন ট্যাব খুলুন
+Name[br]=Digeriñ un ivinell nevez
+Name[bs]=Otvori novi tab
+Name[ca]=Obre una pestanya nova
+Name[cs]=Otevřít nový panel
+Name[cy]=Agor tab newydd
+Name[da]=Åbn nyt faneblad
+Name[de]=Neuen Tab öffnen
+Name[dsb]=Nowy rejtark wócyniś
+Name[el]=Άνοιγμα νέας καρτέλας
+Name[eo]=Malfermi novan langeton
+Name[es_AR]=Abrir nueva pestaña
+Name[es_CL]=Abrir nueva pestaña
+Name[es_ES]=Abrir pestaña nueva
+Name[es_MX]=Abrir una pestaña nueva
+Name[et]=Ava uus kaart
+Name[eu]=Ireki fitxa berria
+Name[ff]=Uddit tabbere hesere
+Name[fi]=Avaa uusi välilehti
+Name[fr]=Ouvrir un nouvel onglet
+Name[fy_NL]=Iepenje nij ljepblêd
+Name[ga_IE]=Oscail i gcluaisín nua
+Name[gd]=Fosgail taba ùr
+Name[gl]=Abrir unha nova lapela
+Name[gu_IN]=નવી ટૅબને ખોલો
+Name[he]=פתיחת לשונית חדשה
+Name[hi_IN]=नया टैब खोलें
+Name[hr]=Otvori novu karticu
+Name[hsb]=Nowy rajtark wočinić
+Name[hu]=Új lap megnyitása
+Name[hy_AM]=Բացել նոր ներդիր
+Name[id]=Buka tab baru
+Name[is]=Opna nýjan flipa
+Name[it]=Apri nuova scheda
+Name[ja]=新しいタブ
+Name[kk]=Жаңа бетті ашу
+Name[kn]=ಹೊಸ ಹಾಳೆಯನ್ನು ತೆರೆ
+Name[ko]=새 탭 열기
+Name[lij]=Àrvi nêuvo féuggio
+Name[lt]=Atverti naują kortelę
+Name[mai]=नव टैब खोलू
+Name[mk]=Отвори ново јазиче
+Name[ml]=പുതിയ റ്റാബ് തുറക്കുക
+Name[mr]=नवीन टॅब उघडा
+Name[ms]=Buka tab baru
+Name[nb_NO]=Åpne ny fane
+Name[nl]=Nieuw tabblad openen
+Name[nn_NO]=Opna ny fane
+Name[or]=ନୂତନ ଟ୍ୟାବ ଖୋଲନ୍ତୁ
+Name[pa_IN]=ਨਵੀਂ ਟੈਬ ਖੋਲ੍ਹੋ
+Name[pl]=Otwórz nową kartę
+Name[pt_BR]=Nova aba
+Name[pt_PT]=Abrir novo separador
+Name[rm]=Avrir in nov tab
+Name[ro]=Deschide o filă nouă
+Name[ru]=Открыть новую вкладку
+Name[si]=නව ටැබය විවෘත කරන්න
+Name[sk]=Otvoriť novú kartu
+Name[sl]=Odpri nov zavihek
+Name[son]=Nor loku taaga feeri
+Name[sq]=Hap skedë të re
+Name[sr]=Отвори нови језичак
+Name[sv_SE]=Öppna ny flik
+Name[ta]=புதிய கீற்றைத் திற
+Name[te]=కొత్త టాబ్ తెరువుము
+Name[th]=เปิดแท็บใหม่
+Name[tr]=Yeni sekme aç
+Name[uk]=Відкрити нову вкладку
+Name[uz]=Yangi ichki oyna ochish
+Name[vi]=Mở thẻ mới
+Name[xh]=Vula ithebhu entsha
+Name[zh_CN]=打开新标签页
+Name[zh_TW]=開啟新分頁
+Exec=icecat -new-tab about:newtab
+
+[Desktop Action NewWindow]
+Name=Open new window
+Name[ach]=Yab dirica manyen
+Name[af]=Open nuwe venster
+Name[an]=Ubrir una nueva finestra
+Name[ar]=افتح نافذة جديدة
+Name[as]=নতুন উইন্ডো খোলক
+Name[ast]=Abrir ventana nueva
+Name[az]=Yeni pəncərə aç
+Name[be]=Адкрыць новае акно
+Name[bg]=Отваряне на нов прозорец
+Name[bn_BD]=নতুন উইন্ডো খুলুন
+Name[bn_IN]=নতুন উইন্ডো খুলুন
+Name[br]=Digeriñ ur prenestr nevez
+Name[bs]=Otvori novi prozor
+Name[ca]=Obre una finestra nova
+Name[cs]=Otevřít nové okno
+Name[cy]=Agor ffenestr newydd
+Name[da]=Åbn nyt vindue
+Name[de]=Neues Fenster öffnen
+Name[dsb]=Nowe wokno wócyniś
+Name[el]=Άνοιγμα νέου παραθύρου
+Name[eo]=Malfermi novan fenestron
+Name[es_AR]=Abrir nueva ventana
+Name[es_CL]=Abrir nueva ventana
+Name[es_ES]=Abrir nueva ventana
+Name[es_MX]=Abrir nueva ventana
+Name[et]=Ava uus aken
+Name[eu]=Ireki leiho berria
+Name[ff]=Uddit henorde hesere
+Name[fi]=Avaa uusi ikkuna
+Name[fr]=Ouvrir une nouvelle fenêtre
+Name[fy_NL]=Iepenje nij finster
+Name[ga_IE]=Oscail fuinneog nua
+Name[gd]=Fosgail uinneag ùr
+Name[gl]=Abrir unha nova xanela
+Name[gu_IN]=નવી વિન્ડોને ખોલો
+Name[he]=פתח חלון חדש
+Name[hi_IN]=नई विंडो खोलें
+Name[hr]=Otvori novi prozor
+Name[hsb]=Nowe wokno wočinić
+Name[hu]=Új ablak megnyitása
+Name[hy_AM]=Բացել նոր պատուհան
+Name[id]=Buka jendela baru
+Name[is]=Opna nýjan glugga
+Name[it]=Apri nuova finestra
+Name[ja]=新しいウィンドウ
+Name[kk]=Жаңа терезені ашу
+Name[kn]=ಹೊಸ ವಿಂಡೊವನ್ನು ತೆರೆ
+Name[ko]=새 창 열기
+Name[lij]=Àrvi nêuvo barcón
+Name[lt]=Atverti naują langą
+Name[mai]=नई विंडो खोलू
+Name[mk]=Отвори нов прозорец
+Name[ml]=പുതിയ ജാലകം തുറക്കുക
+Name[mr]=नवीन पटल उघडा
+Name[ms]=Buka tetingkap baru
+Name[nb_NO]=Åpne nytt vindu
+Name[nl]=Een nieuw venster openen
+Name[nn_NO]=Opna nytt vindauge
+Name[or]=ନୂତନ ୱିଣ୍ଡୋ ଖୋଲନ୍ତୁ
+Name[pa_IN]=ਨਵੀਂ ਵਿੰਡੋ ਖੋਲ੍ਹੋ
+Name[pl]=Otwórz nowe okno
+Name[pt_BR]=Nova janela
+Name[pt_PT]=Abrir nova janela
+Name[rm]=Avrir ina nova fanestra
+Name[ro]=Deschide o nouă fereastră
+Name[ru]=Открыть новое окно
+Name[si]=නව කවුළුවක් විවෘත කරන්න
+Name[sk]=Otvoriť nové okno
+Name[sl]=Odpri novo okno
+Name[son]=Zanfun taaga feeri
+Name[sq]=Hap dritare të re
+Name[sr]=Отвори нови прозор
+Name[sv_SE]=Öppna nytt fönster
+Name[ta]=புதிய சாளரத்தை திற
+Name[te]=కొత్త విండో తెరువుము
+Name[th]=เปิดหน้าต่างใหม่
+Name[tr]=Yeni pencere aç
+Name[uk]=Відкрити нове вікно
+Name[uz]=Yangi oyna ochish
+Name[vi]=Mở cửa sổ mới
+Name[xh]=Vula iwindow entsha
+Name[zh_CN]=打开新窗口
+Name[zh_TW]=開啟新視窗
+Exec=icecat -new-window
+
+[Desktop Action NewPrivateWindow]
+Name=New private window
+Name[ach]=Dirica manyen me mung
+Name[af]=Nuwe privaatvenster
+Name[an]=Nueva finestra de navegación privada
+Name[ar]=نافذة خاصة جديدة
+Name[as]=নতুন ব্যক্তিগত উইন্ডো
+Name[ast]=Ventana privada nueva
+Name[az]=Yeni məxfi pəncərə
+Name[be]=Новае акно адасаблення
+Name[bg]=Нов прозорец за поверително сърфиране
+Name[bn_BD]=নতুন ব্যক্তিগত উইন্ডো
+Name[bn_IN]=নতুন ব্যাক্তিগত উইন্ডো
+Name[br]=Prenestr merdeiñ prevez nevez
+Name[bs]=Novi privatni prozor
+Name[ca]=Finestra privada nova
+Name[cs]=Nové anonymní okno
+Name[cy]=Ffenestr breifat newydd
+Name[da]=Nyt privat vindue
+Name[de]=Neues privates Fenster öffnen
+Name[dsb]=Nowe priwatne wokno
+Name[el]=Νέο παράθυρο ιδιωτικής περιήγησης
+Name[eo]=Nova privata fenestro
+Name[es_AR]=Nueva ventana privada
+Name[es_CL]=Nueva ventana privada
+Name[es_ES]=Nueva ventana privada
+Name[es_MX]=Nueva ventana privada
+Name[et]=Uus privaatne aken
+Name[eu]=Leiho pribatu berria
+Name[ff]=Henorde suturo hesere
+Name[fi]=Uusi yksityinen ikkuna
+Name[fr]=Nouvelle fenêtre de navigation privée
+Name[fy_NL]=Nij priveefinster
+Name[ga_IE]=Fuinneog nua phríobháideach
+Name[gd]=Uinneag phrìobhaideach ùr
+Name[gl]=Nova xanela privada
+Name[gu_IN]=નવી ખાનગી વિન્ડો
+Name[he]=חלון פרטי חדש
+Name[hi_IN]=नया निजी विंडो
+Name[hr]=Novi privatni prozor
+Name[hsb]=Nowe priwatne wokno
+Name[hu]=Új privát ablak
+Name[hy_AM]=Գաղտնի դիտարկում
+Name[id]=Jendela mode pribadi baru
+Name[is]=Nýr einkagluggi
+Name[it]=Nuova finestra anonima
+Name[ja]=新しいプライベートウィンドウ
+Name[kk]=Жаңа жекелік терезе
+Name[kn]=ಹೊಸ ಖಾಸಗಿ ಕಿಟಕಿ
+Name[ko]=새 사생활 보호 창
+Name[lij]=Nêuvo barcón privòu
+Name[lt]=Atverti privačiojo naršymo langą
+Name[mai]=नव निज विंडो
+Name[mk]=Нов прозорец за приватно сурфање
+Name[ml]=പുതിയ സ്വകാര്യ ജാലകം
+Name[mr]=नवीन वैयक्तिक पटल
+Name[ms]=Tetingkap peribadi baharu
+Name[nb_NO]=Nytt privat vindu
+Name[nl]=Nieuw privévenster
+Name[nn_NO]=Nytt privat vindauge
+Name[or]=ନୂତନ ବ୍ୟକ୍ତିଗତ ୱିଣ୍ଡୋ
+Name[pa_IN]=ਨਵੀਂ ਪ੍ਰਾਈਵੇਟ ਵਿੰਡੋ
+Name[pl]=Nowe okno w trybie prywatnym
+Name[pt_BR]=Nova janela privativa
+Name[pt_PT]=Nova janela privada
+Name[rm]=Nova fanestra privata
+Name[ro]=Fereastră fără urme nouă
+Name[ru]=Новое приватное окно
+Name[si]=නව පුද්ගලික කවුළුව
+Name[sk]=Nové okno v režime Súkromné prehliadanie
+Name[sl]=Novo zasebno okno
+Name[son]=Sutura zanfun taaga
+Name[sq]=Dritare e re private
+Name[sr]=Нови приватни прозор
+Name[sv_SE]=Nytt privat fönster
+Name[ta]=புதிய தனிப்பட்ட சாளரம்
+Name[te]=కొత్త ఆంతరంగిక విండో
+Name[th]=หน้าต่างท่องเว็บแบบส่วนตัวใหม่
+Name[tr]=Yeni gizli pencere
+Name[uk]=Нове приватне вікно
+Name[uz]=Yangi shaxsiy oyna
+Name[vi]=Cửa sổ riêng tư mới
+Name[xh]=Ifestile yangasese entsha
+Name[zh_CN]=新建隐私浏览窗口
+Name[zh_TW]=新增隱私視窗
+Exec=icecat -private-window
diff --git a/libre/icecat/icecat.install b/libre/icecat/icecat.install
new file mode 100644
index 000000000..1a1f4b16b
--- /dev/null
+++ b/libre/icecat/icecat.install
@@ -0,0 +1,13 @@
+post_install() {
+ update-desktop-database -q
+ gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
+}
+
+post_upgrade() {
+ post_install
+}
+
+post_remove() {
+ post_install
+}
+
diff --git a/libre/icecat/libre.patch b/libre/icecat/libre.patch
new file mode 100644
index 000000000..c36685d89
--- /dev/null
+++ b/libre/icecat/libre.patch
@@ -0,0 +1,891 @@
+diff --git a/browser/app/profile/icecat.js b/browser/app/profile/icecat.js
+index 17c1e93..40f1e2b 100644
+--- a/browser/app/profile/icecat.js
++++ b/browser/app/profile/icecat.js
+@@ -245,11 +245,6 @@ pref("browser.slowStartup.notificationDisabled", false);
+ pref("browser.slowStartup.timeThreshold", 40000);
+ pref("browser.slowStartup.maxSamples", 5);
+
+-// This url, if changed, MUST continue to point to an https url. Pulling arbitrary content to inject into
+-// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream
+-// repackager of this code using an alternate snippet url, please keep your users safe
+-pref("browser.aboutHomeSnippets.updateUrl", "https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
+-
+ pref("browser.enable_automatic_image_resizing", true);
+ pref("browser.casting.enabled", false);
+ pref("browser.chrome.site_icons", true);
+@@ -1844,17 +1839,6 @@ pref("pfs.filehint.url", "http://gnuzilla.gnu.org/plugins/PluginFinderService.ph
+ pref("geo.enabled", false);
+ pref("geo.wifi.uri", "");
+
+-// I'm feeling Ducky.
+-pref("keyword.URL", "https://duckduckgo.com/html?t=gnu&q=!+");
+-pref("browser.search.defaultenginename", "DuckDuckGo");
+-pref("browser.search.order.extra.duckduckgo", "DuckDuckGo");
+-pref("browser.search.showOneOffButtons", false);
+-// US specific default (used as a fallback if the geoSpecificDefaults request fails).
+-pref("browser.search.defaultenginename.US", "data:text/plain,browser.search.defaultenginename.US=DuckDuckGo");
+-pref("browser.search.order.US.1", "data:text/plain,browser.search.order.US.1=DuckDuckGo");
+-pref("browser.search.order.US.2", "data:text/plain,browser.search.order.US.2=Google");
+-pref("browser.search.order.US.3", "data:text/plain,browser.search.order.US.3=Yahoo");
+-
+ // Disable Gecko media plugins: https://wiki.mozilla.org/GeckoMediaPlugins
+ pref("media.gmp-manager.url", "http://127.0.0.1/");
+ pref("media.gmp-manager.url.override", "data:text/plain,");
+diff --git a/browser/base/content/abouthome/aboutHome.css b/browser/base/content/abouthome/aboutHome.css
+index 8635239..e6514bc 100644
+--- a/browser/base/content/abouthome/aboutHome.css
++++ b/browser/base/content/abouthome/aboutHome.css
+@@ -49,11 +49,6 @@ a {
+ background-repeat: no-repeat;
+ }
+
+-#searchForm,
+-#snippets {
+- width: 470px;
+-}
+-
+ #searchForm {
+ display: -moz-box;
+ }
+@@ -72,8 +67,7 @@ a {
+ #searchEngineLogo {
+ display: inline-block;
+ height: 28px;
+- width: 70px;
+- min-width: 70px;
++ width: 28px;
+ }
+
+ #searchText {
+@@ -145,48 +139,6 @@ a {
+ transition-duration: 0ms;
+ }
+
+-#defaultSnippet1,
+-#defaultSnippet2,
+-#rightsSnippet {
+- display: block;
+- min-height: 38px;
+- background: 30px center no-repeat;
+- padding: 6px 0;
+- -moz-padding-start: 79px;
+-}
+-
+-#rightsSnippet[hidden] {
+- display: none;
+-}
+-
+-#defaultSnippet1:-moz-dir(rtl),
+-#defaultSnippet2:-moz-dir(rtl),
+-#rightsSnippet:-moz-dir(rtl) {
+- background-position: right 30px center;
+-}
+-
+-#defaultSnippet1 {
+- background-image: url("chrome://browser/content/abouthome/snippet1.png");
+-}
+-
+-#defaultSnippet2 {
+- background-image: url("chrome://browser/content/abouthome/snippet2.png");
+-}
+-
+-#snippets {
+- display: inline-block;
+- text-align: start;
+- margin: 12px 0;
+- color: #3c3c3c;
+- font-size: 75%;
+- /* 12px is the computed font size, 15px the computed line height of the snippets
+- with Segoe UI on a default Windows 7 setup. The 15/12 multiplier approximately
+- converts em from units of font-size to units of line-height. The goal is to
+- preset the height of a three-line snippet to avoid visual moving/flickering as
+- the snippets load. */
+- min-height: calc(15/12 * 3em);
+-}
+-
+ #launcher {
+ display: -moz-box;
+ -moz-box-align: center;
+@@ -335,26 +287,25 @@ body[narrow] #restorePreviousSession::before {
+ width: 32px;
+ }
+
+-#aboutMozilla {
++#aboutGNU {
+ display: block;
+- position: relative; /* pin wordmark to edge of document, not of viewport */
+ -moz-box-ordinal-group: 0;
+ opacity: .5;
+ transition: opacity 150ms;
+ }
+
+-#aboutMozilla:hover {
++#aboutGNU:hover {
+ opacity: 1;
+ }
+
+-#aboutMozilla::before {
+- content: url("chrome://browser/content/abouthome/mozilla.png");
++#aboutGNU::before {
++ content: url("chrome://browser/content/abouthome/gnu_headshadow.png");
+ display: block;
+ position: absolute;
+ top: 12px;
+ right: 12px;
+- width: 69px;
+- height: 19px;
++ width: 200px;
++ height: 110px;
+ }
+
+ /* [HiDPI]
+@@ -366,26 +317,6 @@ body[narrow] #restorePreviousSession::before {
+ background-image: url("chrome://branding/content/about-logo@2x.png");
+ }
+
+- #defaultSnippet1,
+- #defaultSnippet2,
+- #rightsSnippet {
+- background-size: 40px;
+- }
+-
+- #defaultSnippet1 {
+- background-image: url("chrome://browser/content/abouthome/snippet1@2x.png");
+- }
+-
+- #defaultSnippet2 {
+- background-image: url("chrome://browser/content/abouthome/snippet2@2x.png");
+- }
+-
+- .launchButton::before,
+- #aboutMozilla::before {
+- transform: scale(.5);
+- transform-origin: 0 0;
+- }
+-
+ #downloads::before {
+ content: url("chrome://browser/content/abouthome/downloads@2x.png");
+ }
+@@ -421,9 +352,5 @@ body[narrow] #restorePreviousSession::before {
+ body[narrow] #restorePreviousSession::before {
+ content: url("chrome://browser/content/abouthome/restore@2x.png");
+ }
+-
+- #aboutMozilla::before {
+- content: url("chrome://browser/content/abouthome/mozilla@2x.png");
+- }
+ }
+
+diff --git a/browser/base/content/abouthome/aboutHome.js b/browser/base/content/abouthome/aboutHome.js
+index 77ae98c..1021d12 100644
+--- a/browser/base/content/abouthome/aboutHome.js
++++ b/browser/base/content/abouthome/aboutHome.js
+@@ -3,149 +3,54 @@
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ const SEARCH_ENGINES = {
+- "Google": {
+- // This is the "2x" image designed for OS X retina resolution, Windows at 192dpi, etc.;
+- // it will be scaled down as necessary on lower-dpi displays.
+- image: "data:image/png;base64," +
+- "iVBORw0KGgoAAAANSUhEUgAAAIwAAAA4CAYAAAAvmxBdAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ" +
+- "bWFnZVJlYWR5ccllPAAAGrFJREFUeNrtfHt4VdW172+utZOASLJ5+BaIFrUeXkFsa0Fl++gDnznV" +
+- "VlvFxt7aqvUUarXtse3Bau35ak/rZ9XT26NtfOvV6wFET+FYCQEKWqsQIT5RCAgSXnlnrzXneNw/" +
+- "1lphJSSQ8BB7bub3zW+LO3uN+fiNMcf4jTEX0N/6W3/rb/2tv30smtnXB3zmRi2FQakxQNKX3WkW" +
+- "9S/tgW3HLpmQM543A0BWVSHMYGIwOTDxzxrOf3/RQQfMZ2/SLAvKhTFVBGUqKFONH2QAzwOMF38a" +
+- "wHhYZAxWAqhe/iszp3+b970d/sInc57vz/J8L2eMB2MAEYkBQ6DQ3dRw4dq7AUjcP3rAfPZmLWXC" +
+- "LHKoIAcQAUxaB5EaEfc6AEBhjDEwmcx43/fO9HxT4vkReBIAAZgjgodW3NcPnn1sHgD/iHknn+0d" +
+- "6s8XEUhsXXac/34WAAGw8afuT8GZ3X055YeSJcIsG+pMZwFn0UihezRofPt3G54f/0E8cNMN+Myo" +
+- "8jVTCgYd823PLzrPeIBnABiUQ1F+UoWsVOYb33mkoKp/7/dKyT0AGc47X4s0sjBEoLxbBqAQAMfW" +
+- "Rfe38B4BM+VHUkYOs8mi1FrABbK4dcvK73zwp1M3xYPOxANKBqbpCdXNGb0UwPKRF74xpfDQ0t+K" +
+- "54+IvlKoahmAhaO/mv/ZmicG3tqPgT61ZM2dZMQJOYhIdByRM/F3dCCOox4Bc3oEliqyyNoQCPPu" +
+- "sXceKZqRsigu7pwaWBowiRb46+f9Q1V2wl1nDx09/R7jF30x9adNlN8yPx4DHwht+B/cBIBoRqeI" +
+- "E4hE/oshTcB0wNbT6/o/zrhFyohR5ZxmrVWE+fDxdx4puhGAH4OkPe5B6pykeJAc/7cDEMZ/095Y" +
+- "870P339m+BXs2v4kbCFsm9u2vnpJ3bzR7wAo2B/R2v+PjSnyXcRxtOLUSXFxwAFz5i2SZUIVO82S" +
+- "BWye/vLOIwNvjL8OYqCEfXCmJAZPHkC7sK1REbj2+lmbq86qTVmmfuuyN2cTiREWKCvACgml9kDL" +
+- "7HQksehsZmSdA6yVpsa6P38v3swg7m4vN1dGXrThKGP8yS5fP33j/LEvxKDbl2f2A0YFCtkZQDOa" +
+- "PjLAnP4jrmBGjh1AVhG2ttxfX33++vjY2eeNXf/siLUAzgEwMJZrY2vF/Vu/t4BRqCqgCmj07wMV" +
+- "HXUCzJQfUlZE72ICnANcqNj21h8eiK1AX46gXh29KT9H+rd9XxBjYGCgig7QHOgjPgMAKigXQZYp" +
+- "si4uCOc3v35zY2wF9ufGSgxA7fdd9g8ho9ol4P4ojiQWnSUMMANECrJNy1NWYH8eGfsEvJbLv1IK" +
+- "1XIAUwEtA0xplJMwjcaYlTDeShg8dOgjj6/cJxNYfWIWkHJoh5yyjkSZ8RbB89YBZq4/pXafGeuz" +
+- "b9WciXJxo2B2houqgAjABJCLOwFMqFv57+bBxMIAJm1det3avnl1OYCLAeSgWhofaY1QXQSRuYc+" +
+- "/OiD3QLmUzNdqTBKhRVMADsF5beuToXJB90KtFz+lVIVniXOVUAUqjpXVB4WwPjGTPB8/0zjeTnj" +
+- "ezl43szmKy6vNkDF4MeeXNc3oJyUhfAMkJsJkSxUVrLos6o6z/O8Ucb3phrPzyHKeVTwkpPXseg3" +
+- "Cqe+1SfG+swfaw6KGTAoJ5eyGF3IBeEIJB2AcXxb0FI/L45uFQBMGiu6Z3ai9eqrclBUClFWVatV" +
+- "5GERNT5wEVQnQLUcIuVNX75kFjn60rA5c1d0AoywlkcxfdwZ2LSgbOmBZAv70povu7RcyFUqcZYd" +
+- "Pbxix44fnLv8pbYUOWh+P3ZM9uJRo34xoLDgq8b3YTxvqhqsaPzyJTdmn36msjdyqPqkMhWqBFGZ" +
+- "MtV8uDX4zMjp2zemyEoPgGn4zyOvGzy48A54GcD3Sz1jFrqqE+4uOOvdmb0ASlYEs5mQE9afUdhy" +
+- "0yv3lHzwya/8ZcjgI0+5yssU3QKYkgQ4Ivp60LL1n8kBQfOWuvdnj6uLldgHQKoKxU7HV/eg2y1X" +
+- "XXmXEs1U0ZVb29o//4k5c5P5eQB+s+68aVeUFBTcCxUoS6kRWfjhueecc9SfX3ytA9QTr7eVACqY" +
+- "FDYEwnbB2qcHHg6gLY6ODhpomi77coUyVaojhKH9+ZHzF/wqXiztEg34APxNX/jCvQOLCi83fpy8" +
+- "UsCJXHLYnGdn785S0uKTyyBUBXJZcW5x4bSN56ciyLQcD4Bf/+ThVwwbUvRb+JkoswqAWX5b9Lm1" +
+- "M3uSM/UnUiaCKiZk2blvvnxX0ePxuBNAmpMur51wyLBPzjVeBBoVwIXBk6vuP+SG+LkcuwkWAA96" +
+- "/JjZKnKxkACkkFb5Nztz220xX9bJlWi+6opKFalQlpqlmzZNu6B6SaJ0knKJ/DW5qd8p8TO3x6AB" +
+- "qza1EE06cdmy9wDAY5LjmBTMkQnUnZ42H0ywNF52aU6FK4UY5NySI+cv+E3MCnMM5HyqtwFoO3rB" +
+- "gmuDMFjGjiCOIEQwzH9c+7lzju+JTaYlJ2ehUqXMWWFqeurFxqsAFMVf25Ss9kTOEZdvebClJbxT" +
+- "yUGZoEzwlL/b9tzRX+pOztSfSBZApSqyIrL45buKnkaUJEzLCN5+csxr+ab6fyILkI2OIZYBlx9/" +
+- "2bYvpLgw2+EqKLKdwoceVKJp+tfuEpYKZcaW1tZbLqheEsbj3GV+oxdV3x0GwQZrHUIiWKIST3Vm" +
+- "DG54zFrKrBBWiGgSyx9Uv6Xh0n/MKlGlOII4h80trQ+kuJt8HGklZHg6FZF/Y/uOb7O1YOvAzkGt" +
+- "Kxmoehe6SYNEpkErwZIFC4I2fuLKf2tLtDOPzumPhA6wAPJDLt1yuzjaAEcAMUCMApXfvPP7IcO6" +
+- "gkYFs4RRpgy49qanUsAPu/T8W48e/YwL6S/kYtBYwM8U/yu6KVlQUShr9CkKyK7b1vDVy0qVeaYy" +
+- "gaxbdeK85/8a/z7sYR3zgXM1gXUInEPoCEw8PR6z8YQxaidQPh6RrgrPEOZS4chKjFuydEEKFD1x" +
+- "QgrAnfO3V98Jw/B5dhFgmByU+MK/nnrq6K6gcQtPyqlIubJAibCxPv/fsVVNgCI9yGEAQdBq71NH" +
+- "UEdQIoBo5PBBeklazuQfSpYFM0UAFsDmd2yMf9+1XkUT3otc8AiRwpFChCBCI0detGbSLtYr5uw6" +
+- "tk26XctZwgxhRt65ZSmr1t389M1Jk85wzKcHRAiJkCfasDnI/0sMGN+jlLMrAigMhp0+f+TBBIw4" +
+- "milEYOcQBHZZAoZeEIgKgIIgeJbD2MqEFhxaDAFmdAWMisxQFigzlAUnX9e4rA9yeHuTna3koBQB" +
+- "RogxwOPvxNbQAAA7VHQEFKSQKEFIu4lA5d3HiiuFNB4XQZlhUHBK11QO0oRdD7ouROVCkeJZG7ak" +
+- "/KBOYHlz4sTy1WVlVY5oYego2+bs82+3tFw6YcVrp01dteqpxNfyhKQuGlxCMSsKBh570ABT/8XP" +
+- "5dhRVpyDWAd2Ns0O9yrhWdfcMpvCEByEoNCCwhBgvgBdM+PM5TH5FPW+1ZLo8de2viehe12dhVoH" +
+- "OAtDPO61O4o+kYCTnE5wVuGsxlzKHul7BUDKdomKgwpB2QHAyNiP2Dl+0Z2WRXZ9YP0F55WJczvX" +
+- "0jp09U3fLiurWD1+/NqQaHZIVNbu3O1vt7aM+fSqVRWXvPvu0pRldwAkQ5brjO+NMh0kgMIvGjYZ" +
+- "wIKETPxIrYt1U5M8iThKJil9yZGc++ab298dP36Jb8wZohqhQHRErKEeAA6fG5FT5yIlYYI6tzfO" +
+- "vtiQni3MYDw0ChqEgUMyejyAdwGwDeW4ZI9FAGQOmwzgv/cERmZbDXhnKBNUGMJkUhGVduSSJJ1P" +
+- "6rw8HIalJo7ilBkchgCgL48fVzLceDc4kZnWUdap1AQi10x+660n4jXyk1M7ZXEZgHhMUkMO4Njp" +
+- "hQGMf8h56Fx++ZE1a+1xZC2Szjs3sk9uUEhUbSMvP3LeyOGZ0tKJiearo1J1DHVRPYmS7JUcG2g1" +
+- "pxxUsooBnpmQWAOb10YbKGygcKFCZOC0XqxrRKokCBQG5euX77In2k1P+2hhWEZBAAoCuCCEcW7E" +
+- "2xMn/m6oYo0jyjnmuc3Off6UN96YMvmtt5LILSmQ61r3xAA0I+xqPBiIejAd1f7e2MPPfvm4LQs/" +
+- "89a+bP6nZuSzfsaU+T7g+UBixYQVRFGS01kFO22srRy0EgA4CEvFRHS3MANMY/fGbybmlQqAFSBV" +
+- "sCp8kWwCGA5dqefFShnnRV77ecHYU37iXuqLoB0tsuIo34v3NfJR1GlJsrnOuiXGy1y8k+rwxh57" +
+- "3srSD/6rbLdra7yMqgjUCGAULR8uWr0LJPYAGApCeCbKNygLPKIxJ65YOSU+YpLUUCYGiqBzQVy3" +
+- "Ft1zbevnJl60UARqACgcVDo9ZZr63Mqua68QxlpmrWJC1FmrmLSKCFVktcpZrbKhzg4D26E5Lgjg" +
+- "8vnoMwwh1hU/dvTRo/qcDyJqcESw5Dp6o3XNHVrqLDSubAdFjuXwwWZcX+Wc9APboKxQUoiLurXa" +
+- "IYfCpjlCDsoxZ6OCouLRt+xpbY3nA8aDMR6E2+9vffOWxl02cQ+Bbdjevt7l83D5ABRaKNHYO484" +
+- "YmgMkoJ4jElCOL8Lz9NN87YumrRDxc2DElQZKgIVhZcZcO1hZ74wtK/H0thvtuXGXdM2S0S/ziQ1" +
+- "FPJiG7pHwvbgDhtKnQ0VNhCEeUHQLmiuf2fymieGvJGY8DCfX+yCEC5xWIlwtO+P6+s4VESJGS4+" +
+- "liwxKjZ/2FGRZvPhYgktxEZdHWOAr2P34ihWIQWTgJ2CnWJbo9Ymz1g/5+h1QsF9wgKJ19Z4hV87" +
+- "4fKNE3cnx8v4V8H4UOjqhvce+zW6qdWVlOvSjQsDlw/WUT4A5QNQGIJDizMPHXR+CiRBb4GSzlYr" +
+- "26Z7vYKSC42nUOPBqA9VU1I0ZOJPEYWj1NvVW/3AoEUAFgO4IzZ1hYk2jf9WUw7IjCIXHUVhXrFp" +
+- "/sQtKZPIoXXr/PjoSkZeoHo6gP/bFyeciECqcHG3IrXp37a2SF3xQNPxRAXgq5nS1bHsDWCYALYA" +
+- "u+h0W/impI8Pad9ec/vAoWVTjV84Nsn5FAwcvmDMN5rOqf1jyatdHzjuGjvThloKYH3b5qVXt775" +
+- "44ZuN1QEKknF3a6ImfDee4tWjBrV6R5Qoeq1AP6Avaxx8gDolhdPXAh2qzQmZFQ4ZhALrj/mvLpT" +
+- "+qhxya0BP5VVZQBkA6jNR0AJ2xUUcjKGjsx4k3PVYUwaJU6rJ3reLiHlHppjBjF3fLYSzU/noEZ8" +
+- "3611VusoVJBVsFWAdezim/3jemSFe+SNIsvCpAhCXf7TBZI+PnTr4nO2t2xcME3ZroYKIouEEqDo" +
+- "xfHfav/GxOttFgBOucGWll0XVqrqXYDWNLz3aG7bsovWp4i2TvkhScLqNBezq/M/zxLBxV2Yx/75" +
+- "yCPP6usc04CJ+B3bcLMwQTiK+0UIwgz1ip8+4pyaYX0x0SnWMkjnYGygkm9nBO0MGzoI2TTDyQBw" +
+- "7ubNawPmeZYZNt5wZhrxX8OHX9yXSTJzGcVgIWasbs8/hc7XRzXM670cg0Vs5H+MHm6u74ucrb/K" +
+- "lAlFPoySoqFFn+rm+OCGV762df2cYWe4fP0M5qDWhoowRIm1/h+s1YZx3wrVOV1LDhXMaGzfXntF" +
+- "46vXtMQRS/clsqRRT9SNd0GMBo6edRStZbKeg4D//ciQIcP2CTDbqsdVKQePq1JMFkXxv4qO9AaM" +
+- "fPGoaeuG9kXp0LkU0wGgMFC1gYAdAeyg0m3IrE3W3mtTvodjRpHq9X3xL4h5Qsq63P/z9ra6LqSc" +
+- "vvmBPkwOTex2lnf4wNee/47fa99NGGVJ8Zl1qP3UPfwkdr15mDDV+Y3Pf+Kh9c9kz9pee89J7dve" +
+- "vaRt+7qLbVv47y5UUKggp3BB/okNz0/aHI8332OaIgELxWDpptQtt6X+Qcu03nVYGQYxjxzl+7/e" +
+- "GyvjdYrCtv31JiW7QTjy6qWj83jF4AeP/MLaodiHRtZBXAihEEIWkq4eSgGmvKGhqpX5d1YEVhiW" +
+- "BaI6Zf6QITN7s5ELhw4tZZavkwhIZMOC1rZfo5s64nPv4+1NzXot2/hYiqKckglH4/7eRojCOosp" +
+- "St6u2ijfS1Hv3I0SdVy5aam9ecumBeOqN8w7aRkxSlMVdRDmRHa4m5xWPKPEusUA6maIrcy/cCKw" +
+- "InASKaCoXrlo2LAH+xpMpAEjLauu2ObaNnxVmZqUHaI8SaR+KnIhTPHCo6ZtOn6vk4qUPNNGnV2P" +
+- "J0ptENweMq92zHBMcMwwIrfMLS6etKdJEnMlCYOZm9YE4dUPkWvsIUckJ/+SZwd5PCEOEBc5rh7j" +
+- "grqf+VfvSc7mO/xZSihVAra3YMY/PqqrUhZVe7C8yRHTBqAVQJuQN5idgJ2ASQAz4PJjptWevKc0" +
+- "RZQ0TQATRWDd/dmFDQ2VeaLH0z4dRVTK9EXZ7IqFJSXH7W6eLw0blntp2NAydGOSqPGVs/5mW9Zc" +
+- "JGKbRSxELIRDCFuIuAmiBa8eMW37rcdc1JDtM+3PYdSp43k9/ulPgmDrsnz+vFBktRWBZYEVKSlU" +
+- "feH5wYPP7u5Hfy4uzi4oLq50IjkSaXrf2vIfBPnV6PlKiwKg0XfyNe2BPkmJ8+oUGeh/bLjNu7En" +
+- "0Gy+w5sppLcyKRra9IZJ98hTvciop9MPSSFUwGTnEjHICsgpyKHYHzjquWMvrJ+wewUENPFjCIAx" +
+- "k3uStyIMbw5FVieWJvJpBE5kgqq+X1VcPGdRcfHMxSUluSUlJbmlUZ+1tKRkLRGVnrZ9Rw12rSLt" +
+- "sDpFg8vmfbpw0HH3wcuMMSaiao2XAbwMjPFhPL/ReN6DfsY8tHHekN0WXR929vqsCpWruFshPEqF" +
+- "o3IyADuWTxgea1rYTbRVeEMmc+SnCwp+OcB4l3kmLq0D4BnzkA/MMUBjvDMXC1DBqlkCFr9N9E//" +
+- "HIZpPyDsQVuTFwsMfP273k8GFeLbvo9izwe8DGA8VMPgIc/D2piALlPFDGWUMqNuazOun/RbeQU7" +
+- "L/zl0cfC+SPOXjG84NBRawCvJNoSE7PiBgr5Xx/MKf7jLnzIbUPKlHVF5C11KgJfD9+shY8Vxjd3" +
+- "0780rEvP8bFDDvnVQGO+lU5MeTDwzM5aTbOzNyrw/XNbWx9JFLknk+sjqjobUHJq9XS/cNj3jZcZ" +
+- "Ac9PwBIDyAeMD2O8RhhvpTFYqYpGqMQOM2UhlFOhsvjfgNJ6ofxyoZaXbHPt8mDNjDU9ACYBbyGA" +
+- "AT/KZEZ/MpO5qciYyRlgROeJGSh0nQCL21Ufmx4EL8dMpqScRt4DFVAAYMCtORx+0Rhz7aFF+GJB" +
+- "BmNM/JKklGo1KlBtHZ474U79P9hZOZcQYb0unD/mwu05qADCZwE4C8Y7I3kTk4kFx+mUuzfMKf5e" +
+- "+rn+rUMq4PR4hFII0gw0xpdvGAWGoDqHf9m8IuV8m2Qtf1pQMPok37+50JhpHlC8EzwRcAzwOqs+" +
+- "Vkv06I+da04nInd3RvuxgCIAhcUTF5zvFQ79oucP+Cy8zIjE6qQnt5Pviu5IqAogVKNCNSrBUte6" +
+- "blnrqi/Vo3O9rI3Pc7cbP6sgGQcAf7rvl3zK908uBKjAGK5jrrmNKKHj/RS3E6L3V2USLUzkZAB4" +
+- "i75pTivwwQMyoKYQ685+QOtScvzUHPbIlJ54ZVsuDPTrZDmnQqUQggo1qkoNRDyFeJ6XGQfjF0fW" +
+- "3O9YWxW6adNzw36Dzm/JKEJ0k7QgtfiSygd1vSrkdZ3jlb6fneT7Y+MN1xrmVX9gbkw9q1MdsemF" +
+- "U5wkpwqSRSw49gfZAcPPHOsVlIww/sBjjPEVnqfGZEQlWKVCjWK31TW/dv56pCruU126TGxPl+US" +
+- "IrAgNQ7TQ+pNukQqfalLNimApvMt6CZMTvsiu3VOJ17XnrNWZ9m85oK8Qmz4sFB+CeXrF29dfOqG" +
+- "1PwKs6fOKyvKjrnb8wrHGD8TWfCOEoX85zb96dgXY9leN2NM+y3SJZG4u7XsSldIykFPz09NHxbR" +
+- "T2U3M11AsKf8aRqtnBqQoG91oWkGOS0/XaQo2Pf3u5mUDK9LukD7Mv5Tv9teSQ4VzipsINUtW9Zc" +
+- "t/mFiRu7WbcOuQNP+MXQ4hGX3mEKBl1mjB9bbwAqSz6cf+TZ8Qaabta/u6hM92ItpZs5dvyor5R/" +
+- "dwvp9QAa6eFzfxRlpVMk2mXh93czeyPn1Bn5ShWtYAJsyEve+OPgC7Hzmgx3USDtejQedlbtDX7h" +
+- "0Ns6HChV5LcvP7rpb1+qx/690dHrtewL05c2c7ZLtrM91fOpDGjXyvT9+WYBPQAg3NPcey1n4vVt" +
+- "FUJSIfGNjJZNy2ekkqzpazIJOefSoTaA9q1VY+5Wbvs9NAoYVBkFh5Sesi9lJ/u6lt5+WETpoi2M" +
+- "PpZU/k9szmKGtVGRWBjQ6g3zP78pxfSGKb+tJ4LPAsi31S/+uXCUlVZmCIc+DlI15L4Cpr/1FA1d" +
+- "0VLqAilzgcCGChdQc5eoTXqpkNS66hv1YLsUElURiG1sOZj7lunf3v3fwlBKjRfX9EjEHKcscV98" +
+- "D40zRKIqgEpz4yvTVnfjU/VbmL/r4yhwTTbPCNsZNi8g50/OnvbCsXu5wQqVURCBuOb7seu98n7A" +
+- "/L23Tc8NX8mW6pL73UoOhYPH/GJv/I7Dzlqbg5pRUG1q++A//+Ng+4f9gDlATVzLHfErZiHioKrn" +
+- "H37uhgeG597sdYnIYeeszypQqQawre9dHNbd0Yj9/5KnfsB8DJpuXXj8Q+ryj3dUZglD1Uz3MsWv" +
+- "HX7uh1fv6QGHn7upAmrWQpEV2zSt+bVptamw+6C9VaP/hcoHrvkABgydUjPLywy6Oboh6HW6PgLj" +
+- "LYqStqYRQHKDMQflMhXOQrnata27tvGvufrEn8ZBfmdPP2AO7NpmAAw85B8qTyjKlt1svAHTjPGL" +
+- "k4w0jAcTAyllnBoh9Kxw/tEdS8cuT0WyH4vX1PYD5qMBzQDE2eFDxz09zsscWuwVHX6a8YwaFAiM" +
+- "NAkHr4vdUdf82rQN6JwnSl4N4vAxeKdxP2A+mjXuKTvcXcY9TdOnyxPk4zKZ/vbRAqe75C3QfZZY" +
+- "0P/y6/7299z+H4QrdGsoib8JAAAAAElFTkSuQmCC"
++ "searx": {
++ image: "data:image/png;base64,\
++iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAACXBIWXMAAB8/AAAf\
++PwHBe4GKAAAAB3RJTUUH3gELEhkV5/5DowAAAAJiS0dEAP+Hj8y/AAAHnUlEQVRo\
++3u2Za4xdVRXHf2ef173z6kxnOjPMzE2pbVOJlKYipYE0Ko0EKfiKBpuABY1CTCDY\
++RL9ASGiCfiDEUKOBGAFRgeCLQE1aP2jTCCnFgoq1pUNaCy0thdoW+ph7z9nn74ez\
++77l3ppS5MzWDH1g7557csx/rv9de67/XPgc+lA/lQ6nLTS216vT6vSFvkB6CFlov\
++al39eRx7/wbel8xTwf7grfBYdDw8Fh4JDvnPe2tpf99OjzO7VQCfRiw/i+oV5qEw\
++i1VWuzrV5UqH2lRSqGCLuY7oLKPu5v5WAXwf8ch7PJ9lXo5smzrVrdnq0xwNaEAD\
++6lefetWjLrUplj/Gte/Rdx7i8GSKjbtfBlxH94TKO8Nj8YUlUyIvZcqU3FUunpUo\
++xdHT/u/pnzD2BqDMnEmW1t0PMQC8zEVFTWS2hktDQkICfHx8DAYPg7CAJcOSYklJ\
++SEjesYt0qOj/FZ4EqizhlVYAJM6r7+QeAALzYrQ4ogGgygJWciG9RKS8wyv8hW2E\
++UFdPjVrVrtSzAMxmHx1AyjJeasUHasiVLwAlM1pSl+ZoSOdrgS7Sau3QmfK21mqp\
++FmieRtSvHrUrkDcXmMVbbrSEi1tzwkMFALHGPJGrH9Y8zdcV2qmzy2F9R/M1XxUN\
++qEdtCt705vJqMVaNxa0B2NwA4ClSp/o0rHlaqNs1uazXRzVfFfWrWyUZNU3mFHNb\
++i4KtjUc+Efnqw/X8sAX0t3J/0ScibK5KeKs1AJsaXhkSEBARsoq7WqSRK7mVjMg5\
++bBNL7+LU+/f03b3Kt4gBAiIiYmJiflNUTy6X8Cr/dnbPsPXHt7GzNQsc5IXm+QeI\
++B4lJsU0lG1eaa1ISbkOub1AHfpTftcqEsCb/6zsjLmYJVUc0deX2DDh19RbLQlaB\
++6+8ArJ/ccg0A+3kAjIMgVsKE+VssEVW28U8ivAk1KSdZ6/jSx+QM96OpAIC7OZnT\
++rcFyFSnpuPmLd1nLEJ9jJcP8etxCpFgS2ljk+hs8uJ4jkwNo9rITZiS4JCIiYIhv\
++U3UOhbuf4BqepewCdCOHuZqqg5a5+9/YiyUlw/4ru6UV5zXj/i3wMHh4fIxqYYEU\
++SwY8wMEmvD6/YnOTFfKWFfJlBK/TeFMG4FWM258GqTZ5QIbF5+kJXSM2uZCrA03p\
++QXh4GOhqLXzHZ3blXL1H5OadW0R4wGuUJnR+nYwUuUUQahrOC7xpADglBIgTWFK3\
++9+cAUjpIJ3Ruw2KdBwiLOAnOZ5SIKS+B9uZMBq9hScbFQZVLG+14jF34LCVpWgBL\
++ypt4zm05ztQBsD2fDewo1jYlJSHlNDcU2YvlOEfp5JpxLVIS9ruIEU250RQs8IfM\
++DfAuuwoL1G2whHsxJAjDDXyNR6GpRQ5iXxGW2ptpyj6g57PMGosl5k+sdpTi42Ew\
++ZCxjI7/k77RxBZ/nFMm4vUEcZH8RltramgUmuGqwOf5kiTIxQ/wAHx/PXcaFV06y\
++GdbZqlEi7mCUGmOMcZrkfPZN3QfINlgsCZY32AIu3UyoFVeVMcaoFjWN8iJ7yOoO\
+++Y/W1J9hAdqDE2ViYkpE3MUAfsHtuQ0akaCCATIyDHfzGlXGqHKa9OPZS60BmJhx\
++JNS8lXWFe1leUEwjC6j/po6C8/IwL5ORYKmR7rTryKZnASgFu+NKnhFFVLidoLCB\
++V9hA0AQMNrKRmgvF05hr39nQaiZlzngyZm+vFev+Ous5TEr1jDLm7jXG+DnPUCPF\
++InxCXb5bQWrkTc8CgLkvXBsTuRKwmkWETfOv+wBY3uAR3iWlRkKGhw+kp5ZetmkH\
++mZdNEwC++XO4Ii4SbY9BFnMps5zreYAh4a9s5wCJO5zVyBARJTxqta6bR39xnG47\
++PQCA2RKtCF2iHRDgkTHEXGZTIuEoB9iLh+cYMAdgETElYgxVZn1z96NjtmynCQDf\
++/DS4KT+c+oTF2dhrCsI8FtLieGox+C6EfRLMg2/cciToTafmhHWx2deTm2v/qUf2\
++aU4z5kio6tguv/J/tT9aICNljFNUsYRkNw8+9UyHfGumY4EcXxs/878aNL0d8PBc\
++ztBIzNM92Wc1yo08lA/pE1EiJsCSjB5ejMV6YtpygX9fsCdSWW3qUKc61akOtaus\
++WOEJ/wlvVdFyFSfz422gsno0qIqG1b//MxdAZs71Nd6wd4f/nH8yqIW1sBbU/FHz\
++E+/SM1otzHcpT75K6taAKhpWr5YtV3juEOobeFt+ijyLDLK7DiFWlwY0ohH11+Z9\
++A9L/EYTJZVsOwShWp+ZoRBX1q/I9xfJb48dzFZ+H8kg1itShPg2rogH1P6ng4AxB\
++gHV1CKHa1athVTSowd/e0y0zUxCurr/yCdSuXg2povPUN7qu9+1wpiBc1QjLNvVo\
++SBUNqe/A8iXyj84QhH6O1GOirG4NakTD6jt55QUKNEMxMcQL+VL4KmmWY4Y+LfmU\
++IjtDEEK21yFEDWY4/nifIvkzxQzrG2GZM8OIhl6pdimeuS8y9zbCMmeGEV1+ozpn\
++jBz5Ll/Gbdj59m45egkzpx+ACzmQx0SoNnUfX7M0nTXTn8YifuzCMv3ER1RS6YP4\
++PncxD/Oc+aK81Jfv8cGIh0AflPb/K/kvIVmE2W8jhuAAAAAASUVORK5CYII="
+ }
+ };
+
+-// The process of adding a new default snippet involves:
+-// * add a new entity to aboutHome.dtd
+-// * add a <span/> for it in aboutHome.xhtml
+-// * add an entry here in the proper ordering (based on spans)
+-// The <a/> part of the snippet will be linked to the corresponding url.
+-const DEFAULT_SNIPPETS_URLS = [ "" ];
+-
+-const SNIPPETS_UPDATE_INTERVAL_MS = 86400000; // 1 Day.
+-
+-// IndexedDB storage constants.
+-const DATABASE_NAME = "abouthome";
+-const DATABASE_VERSION = 1;
+-const SNIPPETS_OBJECTSTORE_NAME = "snippets";
+-
+ // This global tracks if the page has been set up before, to prevent double inits
+ let gInitialized = false;
+ let gObserver = new MutationObserver(function (mutations) {
+@@ -153,7 +58,6 @@ let gObserver = new MutationObserver(function (mutations) {
+ if (mutation.attributeName == "searchEngineName") {
+ setupSearchEngine();
+ if (!gInitialized) {
+-// ensureSnippetsMapThen(loadSnippets);
+ gInitialized = true;
+ }
+ return;
+@@ -178,118 +82,6 @@ window.addEventListener("pagehide", function() {
+ window.removeEventListener("resize", fitToWidth);
+ });
+
+-// This object has the same interface as Map and is used to store and retrieve
+-// the snippets data. It is lazily initialized by ensureSnippetsMapThen(), so
+-// be sure its callback returned before trying to use it.
+-let gSnippetsMap;
+-let gSnippetsMapCallbacks = [];
+-
+-/**
+- * Ensure the snippets map is properly initialized.
+- *
+- * @param aCallback
+- * Invoked once the map has been initialized, gets the map as argument.
+- * @note Snippets should never directly manage the underlying storage, since
+- * it may change inadvertently.
+- */
+-function ensureSnippetsMapThen(aCallback)
+-{
+-return;
+- if (gSnippetsMap) {
+- aCallback(gSnippetsMap);
+- return;
+- }
+-
+- // Handle multiple requests during the async initialization.
+- gSnippetsMapCallbacks.push(aCallback);
+- if (gSnippetsMapCallbacks.length > 1) {
+- // We are already updating, the callbacks will be invoked when done.
+- return;
+- }
+-
+- let invokeCallbacks = function () {
+- if (!gSnippetsMap) {
+- gSnippetsMap = Object.freeze(new Map());
+- }
+-
+- for (let callback of gSnippetsMapCallbacks) {
+- callback(gSnippetsMap);
+- }
+- gSnippetsMapCallbacks.length = 0;
+- }
+-
+- let openRequest = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
+-
+- openRequest.onerror = function (event) {
+- // Try to delete the old database so that we can start this process over
+- // next time.
+- indexedDB.deleteDatabase(DATABASE_NAME);
+- invokeCallbacks();
+- };
+-
+- openRequest.onupgradeneeded = function (event) {
+- let db = event.target.result;
+- if (!db.objectStoreNames.contains(SNIPPETS_OBJECTSTORE_NAME)) {
+- db.createObjectStore(SNIPPETS_OBJECTSTORE_NAME);
+- }
+- }
+-
+- openRequest.onsuccess = function (event) {
+- let db = event.target.result;
+-
+- db.onerror = function (event) {
+- invokeCallbacks();
+- }
+-
+- db.onversionchange = function (event) {
+- event.target.close();
+- invokeCallbacks();
+- }
+-
+- let cache = new Map();
+- let cursorRequest = db.transaction(SNIPPETS_OBJECTSTORE_NAME)
+- .objectStore(SNIPPETS_OBJECTSTORE_NAME).openCursor();
+- cursorRequest.onerror = function (event) {
+- invokeCallbacks();
+- }
+-
+- cursorRequest.onsuccess = function(event) {
+- let cursor = event.target.result;
+-
+- // Populate the cache from the persistent storage.
+- if (cursor) {
+- cache.set(cursor.key, cursor.value);
+- cursor.continue();
+- return;
+- }
+-
+- // The cache has been filled up, create the snippets map.
+- gSnippetsMap = Object.freeze({
+- get: function (aKey) cache.get(aKey),
+- set: function (aKey, aValue) {
+- db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite")
+- .objectStore(SNIPPETS_OBJECTSTORE_NAME).put(aValue, aKey);
+- return cache.set(aKey, aValue);
+- },
+- has: function (aKey) cache.has(aKey),
+- delete: function (aKey) {
+- db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite")
+- .objectStore(SNIPPETS_OBJECTSTORE_NAME).delete(aKey);
+- return cache.delete(aKey);
+- },
+- clear: function () {
+- db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite")
+- .objectStore(SNIPPETS_OBJECTSTORE_NAME).clear();
+- return cache.clear();
+- },
+- get size() cache.size
+- });
+-
+- setTimeout(invokeCallbacks, 0);
+- }
+- }
+-}
+-
+ function onSearchSubmit(aEvent)
+ {
+ let searchTerms = document.getElementById("searchText").value;
+@@ -339,159 +131,6 @@ function setupSearchEngine()
+
+ }
+
+-/**
+- * Inform the test harness that we're done loading the page.
+- */
+-function loadSucceeded()
+-{
+- var event = new CustomEvent("AboutHomeLoadSnippetsSucceeded", {bubbles:true});
+- document.dispatchEvent(event);
+-}
+-
+-/**
+- * Update the local snippets from the remote storage, then show them through
+- * showSnippets.
+- */
+-function loadSnippets()
+-{
+-return;
+- if (!gSnippetsMap)
+- throw new Error("Snippets map has not properly been initialized");
+-
+- // Allow tests to modify the snippets map before using it.
+- var event = new CustomEvent("AboutHomeLoadSnippets", {bubbles:true});
+- document.dispatchEvent(event);
+-
+- // Check cached snippets version.
+- let cachedVersion = gSnippetsMap.get("snippets-cached-version") || 0;
+- let currentVersion = document.documentElement.getAttribute("snippetsVersion");
+- if (cachedVersion < currentVersion) {
+- // The cached snippets are old and unsupported, restart from scratch.
+- gSnippetsMap.clear();
+- }
+-
+- // Check last snippets update.
+- let lastUpdate = gSnippetsMap.get("snippets-last-update");
+- let updateURL = document.documentElement.getAttribute("snippetsURL");
+- let shouldUpdate = !lastUpdate ||
+- Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS;
+- if (updateURL && shouldUpdate) {
+- // Try to update from network.
+- let xhr = new XMLHttpRequest();
+- try {
+- xhr.open("GET", updateURL, true);
+- } catch (ex) {
+- showSnippets();
+- loadSucceeded();
+- return;
+- }
+- // Even if fetching should fail we don't want to spam the server, thus
+- // set the last update time regardless its results. Will retry tomorrow.
+- gSnippetsMap.set("snippets-last-update", Date.now());
+- xhr.onerror = function (event) {
+- showSnippets();
+- };
+- xhr.onload = function (event)
+- {
+- if (xhr.status == 200) {
+- gSnippetsMap.set("snippets", xhr.responseText);
+- gSnippetsMap.set("snippets-cached-version", currentVersion);
+- }
+- showSnippets();
+- loadSucceeded();
+- };
+- xhr.send(null);
+- } else {
+- showSnippets();
+- loadSucceeded();
+- }
+-}
+-
+-/**
+- * Shows locally cached remote snippets, or default ones when not available.
+- *
+- * @note: snippets should never invoke showSnippets(), or they may cause
+- * a "too much recursion" exception.
+- */
+-let _snippetsShown = false;
+-function showSnippets()
+-{
+-return;
+- let snippetsElt = document.getElementById("snippets");
+-
+- // Show about:rights notification, if needed.
+- let showRights = document.documentElement.getAttribute("showKnowYourRights");
+- if (showRights) {
+- let rightsElt = document.getElementById("rightsSnippet");
+- let anchor = rightsElt.getElementsByTagName("a")[0];
+- anchor.href = "about:rights";
+- snippetsElt.appendChild(rightsElt);
+- rightsElt.removeAttribute("hidden");
+- return;
+- }
+-
+- if (!gSnippetsMap)
+- throw new Error("Snippets map has not properly been initialized");
+- if (_snippetsShown) {
+- // There's something wrong with the remote snippets, just in case fall back
+- // to the default snippets.
+- showDefaultSnippets();
+- throw new Error("showSnippets should never be invoked multiple times");
+- }
+- _snippetsShown = true;
+-
+- let snippets = gSnippetsMap.get("snippets");
+- // If there are remotely fetched snippets, try to to show them.
+- if (snippets) {
+- // Injecting snippets can throw if they're invalid XML.
+- try {
+- snippetsElt.innerHTML = snippets;
+- // Scripts injected by innerHTML are inactive, so we have to relocate them
+- // through DOM manipulation to activate their contents.
+- Array.forEach(snippetsElt.getElementsByTagName("script"), function(elt) {
+- let relocatedScript = document.createElement("script");
+- relocatedScript.type = "text/javascript;version=1.8";
+- relocatedScript.text = elt.text;
+- elt.parentNode.replaceChild(relocatedScript, elt);
+- });
+- return;
+- } catch (ex) {
+- // Bad content, continue to show default snippets.
+- }
+- }
+-
+- showDefaultSnippets();
+-}
+-
+-/**
+- * Clear snippets element contents and show default snippets.
+- */
+-function showDefaultSnippets()
+-{
+-return;
+- // Clear eventual contents...
+- let snippetsElt = document.getElementById("snippets");
+- snippetsElt.innerHTML = "";
+-
+- // ...then show default snippets.
+- let defaultSnippetsElt = document.getElementById("defaultSnippets");
+- let entries = defaultSnippetsElt.querySelectorAll("span");
+- // Choose a random snippet. Assume there is always at least one.
+- let randIndex = Math.floor(Math.random() * entries.length);
+- let entry = entries[randIndex];
+- // Inject url in the eventual link.
+- if (DEFAULT_SNIPPETS_URLS[randIndex]) {
+- let links = entry.getElementsByTagName("a");
+- // Default snippets can have only one link, otherwise something is messed
+- // up in the translation.
+- if (links.length == 1) {
+- links[0].href = DEFAULT_SNIPPETS_URLS[randIndex];
+- }
+- }
+- // Move the default snippet to the snippets element.
+- snippetsElt.appendChild(entry);
+-}
+-
+ function fitToWidth() {
+ if (window.scrollMaxX) {
+ document.body.setAttribute("narrow", "true");
+diff --git a/browser/base/content/abouthome/aboutHome.xhtml b/browser/base/content/abouthome/aboutHome.xhtml
+index f2e76b8..4b87621 100644
+--- a/browser/base/content/abouthome/aboutHome.xhtml
++++ b/browser/base/content/abouthome/aboutHome.xhtml
+@@ -114,7 +114,7 @@ min-height:100px;
+ <img src="chrome://branding/content/about-logo.png"/>
+
+ <div id="searchContainer">
+- <form name="searchForm" id="searchForm" action="https://duckduckgo.com/html/">
++ <form name="searchForm" id="searchForm" action="https://searx.laquadrature.net/">
+ <input type="text" name="q" value="" id="searchText" maxlength="256"
+ autofocus="autofocus"/>
+ <input id="searchSubmit" type="submit" value="Search"/>
+diff --git a/browser/base/jar.mn b/browser/base/jar.mn
+index 334358c..44148fd 100644
+--- a/browser/base/jar.mn
++++ b/browser/base/jar.mn
+@@ -32,6 +32,7 @@ browser.jar:
+ content/browser/abouthome/settings.png (content/abouthome/settings.png)
+ content/browser/abouthome/restore.png (content/abouthome/restore.png)
+ content/browser/abouthome/restore-large.png (content/abouthome/restore-large.png)
++ content/browser/abouthome/gnu_headshadow.png (content/abouthome/gnu_headshadow.png)
+ content/browser/abouthome/snippet1@2x.png (content/abouthome/snippet1@2x.png)
+ content/browser/abouthome/snippet2@2x.png (content/abouthome/snippet2@2x.png)
+ content/browser/abouthome/downloads@2x.png (content/abouthome/downloads@2x.png)
+diff --git a/browser/locales/en-US/chrome/browser/aboutHome.dtd b/browser/locales/en-US/chrome/browser/aboutHome.dtd
+index 053f07c..f306f0a 100644
+--- a/browser/locales/en-US/chrome/browser/aboutHome.dtd
++++ b/browser/locales/en-US/chrome/browser/aboutHome.dtd
+@@ -11,17 +11,6 @@
+
+ <!ENTITY abouthome.pageTitle "&brandFullName; Start Page">
+
+-<!-- LOCALIZATION NOTE (abouthome.defaultSnippet1.v1):
+- text in <a/> will be linked to the IceCat features page on mozilla.com
+--->
+-<!ENTITY abouthome.defaultSnippet1.v1 "Thanks for choosing IceCat! To get the most out of your browser, learn more about the <a>latest features</a>.">
+-<!-- LOCALIZATION NOTE (abouthome.defaultSnippet2.v1):
+- text in <a/> will be linked to the featured add-ons on addons.mozilla.org
+--->
+-<!ENTITY abouthome.defaultSnippet2.v1 "It's easy to customize your IceCat exactly the way you want it. <a>Choose from thousands of add-ons</a>.">
+-<!-- LOCALIZATION NOTE (abouthome.rightsSnippet): text in <a/> will be linked to about:rights -->
+-<!ENTITY abouthome.rightsSnippet "&brandFullName; is Free Software from the non-profit Mozilla Foundation. <a>Know your rights…</a>">
+-
+ <!ENTITY abouthome.bookmarksButton.label "Bookmarks">
+ <!ENTITY abouthome.historyButton.label "History">
+ <!-- LOCALIZATION NOTE (abouthome.preferencesButtonWin.label): The label for the
+diff --git a/browser/locales/en-US/chrome/browser-region/region.properties b/browser/locales/en-US/chrome/browser-region/region.properties
+index 0b28ba8..3333c1b 100644
+--- a/browser/locales/en-US/chrome/browser-region/region.properties
++++ b/browser/locales/en-US/chrome/browser-region/region.properties
+@@ -3,17 +3,12 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ # Default search engine
+-browser.search.defaultenginename=Google
++browser.search.defaultenginename=searx
+
+ # Search engine order (order displayed in the search bar dropdown)s
+-browser.search.order.1=Google
+-browser.search.order.2=Yahoo
+-browser.search.order.3=Bing
+-
+-# This is the default set of web based feed handlers shown in the reader
+-# selection UI
+-browser.contentHandlers.types.0.title=My Yahoo!
+-browser.contentHandlers.types.0.uri=https://add.my.yahoo.com/rss?url=%s
++browser.search.order.1=searx
++browser.search.order.2=DuckDuckGo HTML
++browser.search.order.3=DuckDuckGo Lite
+
+ # increment this number when anything gets changed in the list below. This will
+ # cause IceCat to re-read these prefs and inject any new handlers into the
+@@ -22,20 +17,10 @@ browser.contentHandlers.types.0.uri=https://add.my.yahoo.com/rss?url=%s
+ # don't make any spelling errors here.
+ gecko.handlerService.defaultHandlersVersion=4
+
+-# The default set of protocol handlers for webcal:
+-gecko.handlerService.schemes.webcal.0.name=30 Boxes
+-gecko.handlerService.schemes.webcal.0.uriTemplate=https://30boxes.com/external/widget?refer=ff&url=%s
+-
+-# The default set of protocol handlers for mailto:
+-gecko.handlerService.schemes.mailto.0.name=Yahoo! Mail
+-gecko.handlerService.schemes.mailto.0.uriTemplate=https://compose.mail.yahoo.com/?To=%s
+-gecko.handlerService.schemes.mailto.1.name=Gmail
+-gecko.handlerService.schemes.mailto.1.uriTemplate=https://mail.google.com/mail/?extsrc=mailto&url=%s
+-
+ # The default set of protocol handlers for irc:
+-gecko.handlerService.schemes.irc.0.name=Mibbit
+-gecko.handlerService.schemes.irc.0.uriTemplate=
++gecko.handlerService.schemes.irc.0.name=Freenode Web IRC
++gecko.handlerService.schemes.irc.0.uriTemplate=https://webchat.freenode.net
+
+ # The default set of protocol handlers for ircs:
+-gecko.handlerService.schemes.ircs.0.name=Mibbit
+-gecko.handlerService.schemes.ircs.0.uriTemplate=
++gecko.handlerService.schemes.ircs.0.name=Freenode Web IRC
++gecko.handlerService.schemes.ircs.0.uriTemplate=https://webchat.freenode.net
+diff --git a/browser/locales/generic/profile/bookmarks.html.in b/browser/locales/generic/profile/bookmarks.html.in
+index e8460a4..374bf61 100644
+--- a/browser/locales/generic/profile/bookmarks.html.in
++++ b/browser/locales/generic/profile/bookmarks.html.in
+@@ -11,8 +11,20 @@
+ <DD>Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
+ <DL><p>
+ <HR>
+- <DT><A HREF="http://www.gnu.org/" ADD_DATE="1245542746" LAST_MODIFIED="1245542763" ICON_URI="http://www.gnu.org/graphics/gnu-head-mini.png" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAGFBMVEVFRUV+fn6mpqa/v7/Ozs7Y2Njg4OD8/Pwuhn+TAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9MBDhQ6Gd8s57cAAAEkSURBVHicXdFNc4JADAbgoP0Bi4d6dcGBMzp2z2rrnjulcsavnKuQ9+83K37vDAN5yIZsILws0uv3i7ugLTnAwpjBOsTLOE4VmmKQTFYBioGNKkI5drcCReRItmNAyinSCjianJo6A/aGRtRjtPadpB5CRkQRUaYPGbXW4UgKMfXQxDnJPIeJ0qyOrclrLXoqou8+5p7HM9EkT/JtyEsqB2QYnRv7sT2ArRPLf0kWOp1sA3hYPq3Oh/t0EAjjVIG703II9awr3l3BhxAf5foMLaaasPEZqm5A+0RzGCmuIKJbWi284csIJbzykBQ3aIADsL2CFtBWpovhA1Td7Q6NzqZ/B+38APG3HxU+sYO4B9Akt+AnqGbp/gmwTN6eAWt+gcv6B4rivVin0bWbAAAAAElFTkSuQmCC">GNU&#39;s not UNIX!</A>
+- <DT><A FEEDURL="http://planet.gnu.org/atom.xml" HREF="http://planet.gnu.org/">GNU Planet</A>
+- <DT><A HREF="http://www.fsf.org/" ADD_DATE="1245542771" LAST_MODIFIED="1245542780" ICON_URI="http://www.fsf.org/favicon.ico" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAADG0lEQVQoFQEQA+/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQECAAAAAAAAAAAAAAAAAAAA2qOp7tTXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAP///wAAAAAAAOCyt7pUXQcSEgcQDwAAAP///wAAAAAAAAD//x9NSDqNhQEBAQQAAAAAAAAAAAAAAAAQJiQGDQ0aPToZPjoAAQEAAAAAAAAAAAABAQEpZV4AAAAAAAAAAAAA////////////////pSIv05KZ////////////////////////////////AAAAAQAAAP///6krNwAAAAAAAPHc3ggSEQcSEQAAAAAAAAAAABY3NEGelQAAAAAAAAEBAQEAAAD///+YARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDg1g690CBgYAAAABAQEEAAAAAAAAS7etAAAAAAAAwGVtHklFIlJOAAAAAAAAAAAAAAAA+/X2BwYGAAAAAAAABAAAAAAAAB1IQwAAAAAAAAYNDBAmJB1IQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAgL//v4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAQEB//7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAECAv/+/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////////cqK3qzM////////////////////////////////8AAAABAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGuLjDf9F8oBAAAAAElFTkSuQmCC">Free Software Foundation</A>
++ <DT><A HREF="https://www.parabola.nu/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4jWNgoCcoq16VU1GzygnEBtEVDWuV8GooKFuhWVG3uiM3d5UokG4qr1szAaa5vGbVt4ralacwNDU0rGIrr10VBVG0+lxhwyqVsqqVtRW1q6eD5IvL19oB2V+B+D9QzQu4xtDQVZylVavygRKHqurWOlbUrknKK12qWlCwWLK8elUFA8N/xvLy5VYVtas+gzWDDVi9E2QjT1XdcufymjWpQJt1cXmnvHwVP1DzR7hmIC6vW+kOtpnYQKysW30arrlm9RVi9cFBRfXKJTADympWJZNsQFnN6rUQA1adAQU2SZqBXmUGBtozUDiU1qxQJtl2oCY3kO2l1avCSdYMAsBAWwyM2plkaS4p6eYGOv1YQ0MDB1kGlFWuDChuWKZBlmYQqK5eJU22ZkIAAEIlnQZQkzITAAAAAElFTkSuQmCC">Parabola GNU/Linux-libre</A>
++ </DL><p>
++ <DT><H3 ID="rdf:#$YvPhC3">Parabola GNU/Linux-libre</H3>
++ <DL><p>
++ <DT><A HREF="https://www.parabola.nu/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4jWNgoCcoq16VU1GzygnEBtEVDWuV8GooKFuhWVG3uiM3d5UokG4qr1szAaa5vGbVt4ralacwNDU0rGIrr10VBVG0+lxhwyqVsqqVtRW1q6eD5IvL19oB2V+B+D9QzQu4xtDQVZylVavygRKHqurWOlbUrknKK12qWlCwWLK8elUFA8N/xvLy5VYVtas+gzWDDVi9E2QjT1XdcufymjWpQJt1cXmnvHwVP1DzR7hmIC6vW+kOtpnYQKysW30arrlm9RVi9cFBRfXKJTADympWJZNsQFnN6rUQA1adAQU2SZqBXmUGBtozUDiU1qxQJtl2oCY3kO2l1avCSdYMAsBAWwyM2plkaS4p6eYGOv1YQ0MDB1kGlFWuDChuWKZBlmYQqK5eJU22ZkIAAEIlnQZQkzITAAAAAElFTkSuQmCC">Parabola GNU/Linux-libre</A>
++ <DT><A HREF="https://www.parabola.nu/packages/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4jWNgoCcoq16VU1GzygnEBtEVDWuV8GooKFuhWVG3uiM3d5UokG4qr1szAaa5vGbVt4ralacwNDU0rGIrr10VBVG0+lxhwyqVsqqVtRW1q6eD5IvL19oB2V+B+D9QzQu4xtDQVZylVavygRKHqurWOlbUrknKK12qWlCwWLK8elUFA8N/xvLy5VYVtas+gzWDDVi9E2QjT1XdcufymjWpQJt1cXmnvHwVP1DzR7hmIC6vW+kOtpnYQKysW30arrlm9RVi9cFBRfXKJTADympWJZNsQFnN6rUQA1adAQU2SZqBXmUGBtozUDiU1qxQJtl2oCY3kO2l1avCSdYMAsBAWwyM2plkaS4p6eYGOv1YQ0MDB1kGlFWuDChuWKZBlmYQqK5eJU22ZkIAAEIlnQZQkzITAAAAAElFTkSuQmCC">Parabola GNU/Linux-libre Packages</A>
++ <DT><A HREF="https://wiki.parabola.nu/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4jWNgoCcoq16VU1GzygnEBtEVDWuV8GooKFuhWVG3uiM3d5UokG4qr1szAaa5vGbVt4ralacwNDU0rGIrr10VBVG0+lxhwyqVsqqVtRW1q6eD5IvL19oB2V+B+D9QzQu4xtDQVZylVavygRKHqurWOlbUrknKK12qWlCwWLK8elUFA8N/xvLy5VYVtas+gzWDDVi9E2QjT1XdcufymjWpQJt1cXmnvHwVP1DzR7hmIC6vW+kOtpnYQKysW30arrlm9RVi9cFBRfXKJTADympWJZNsQFnN6rUQA1adAQU2SZqBXmUGBtozUDiU1qxQJtl2oCY3kO2l1avCSdYMAsBAWwyM2plkaS4p6eYGOv1YQ0MDB1kGlFWuDChuWKZBlmYQqK5eJU22ZkIAAEIlnQZQkzITAAAAAElFTkSuQmCC">Parabola GNU/Linux-libre Wiki</A>
++ <DT><A HREF="https://labs.parabola.nu/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABL0lEQVQ4jWNgoCcoq16VU1GzygnEBtEVDWuV8GooKFuhWVG3uiM3d5UokG4qr1szAaa5vGbVt4ralacwNDU0rGIrr10VBVG0+lxhwyqVsqqVtRW1q6eD5IvL19oB2V+B+D9QzQu4xtDQVZylVavygRKHqurWOlbUrknKK12qWlCwWLK8elUFA8N/xvLy5VYVtas+gzWDDVi9E2QjT1XdcufymjWpQJt1cXmnvHwVP1DzR7hmIC6vW+kOtpnYQKysW30arrlm9RVi9cFBRfXKJTADympWJZNsQFnN6rUQA1adAQU2SZqBXmUGBtozUDiU1qxQJtl2oCY3kO2l1avCSdYMAsBAWwyM2plkaS4p6eYGOv1YQ0MDB1kGlFWuDChuWKZBlmYQqK5eJU22ZkIAAEIlnQZQkzITAAAAAElFTkSuQmCC">Parabola GNU/Linux-libre Labs</A>
++ </DL><p>
++ <DT><H3 ID="rdf:#$ZvPhC3">Free Software Foundation</H3>
++ <DL><p>
++ <DT><A HREF="https://www.fsf.org/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAAsTAAALEwEAmpwYAAADG0lEQVQoFQEQA+/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQECAAAAAAAAAAAAAAAAAAAA2qOp7tTXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAP///wAAAAAAAOCyt7pUXQcSEgcQDwAAAP///wAAAAAAAAD//x9NSDqNhQEBAQQAAAAAAAAAAAAAAAAQJiQGDQ0aPToZPjoAAQEAAAAAAAAAAAABAQEpZV4AAAAAAAAAAAAA////////////////pSIv05KZ////////////////////////////////AAAAAQAAAP///6krNwAAAAAAAPHc3ggSEQcSEQAAAAAAAAAAABY3NEGelQAAAAAAAAEBAQEAAAD///+YARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGDg1g690CBgYAAAABAQEEAAAAAAAAS7etAAAAAAAAwGVtHklFIlJOAAAAAAAAAAAAAAAA+/X2BwYGAAAAAAAABAAAAAAAAB1IQwAAAAAAAAYNDBAmJB1IQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAgL//v4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAQEB//7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAECAv/+/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////////cqK3qzM////////////////////////////////8AAAABAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGuLjDf9F8oBAAAAAElFTkSuQmCC">Free Software Foundation</A>
++ <DT><A HREF="https://www.gnu.org/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAGFBMVEVFRUV+fn6mpqa/v7/Ozs7Y2Njg4OD8/Pwuhn+TAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEQAACxEBf2RfkQAAAAd0SU1FB9MBDhQ6Gd8s57cAAAEVSURBVBgZBcGxVtpgGADQL9gHSBzqSognzMixmcWWzB6pmRHhnyvku6/fewMAIPD3TwHmQxHs6vr+A16bphNum/vV0x429201hcPjAGBTDZGnR/Kw1U181+u4HXvOdSxjUcztz8jjg1xGVBG9XPYxt4PviKiaWLg168iXtbrq+mPT1utjNcR1U73deRnL43M2sRgj3+oYs8uL3rLphPd2QWmHbMu/VS/cnk6UdtSW657g9yBlcZ0UAkUWzPvyRaAYmfd+HT4IZtvC59ibEJxXiqJjQpBpNEufBYE0McoOAunGhRMEFIPc7h4goJigQEBxk8u7AgEpL3IEAUZfcgAByGFXQACm5+4MAuB19QMEgI8CAgDgP4rivVgoKP6ZAAAAAElFTkSuQmCC">The GNU Operating System and the Free Software Movement</A>
++ <DT><A HREF="https://libreplanet.org/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACfElEQVQ4jZXTS0hUcRTH8f+9M3fGd0gRRq1a2bZdBAotWtS6TQtB6IHgKzRy0UKqjRaRCAq+R21MDMsUR83JR5fJxhmaK2lzsWAWw+ToEHJxgnFm7reFIgza66z/58P/dzhHcESZpsluIsFPwyCVSmGa5lHPEEIIkdGYTqPPvqUlP4fK8nJ2DINYNEq71YJ3fv4QlAGkUynaj+VRdfUK7580M52rEN/ZYWNjg2GrjEMSPFXsmOn0YcA0TZ4V5tNZUkJTTTWfJiZIJhJ8U1VczwcZs0o4JUHzufM0ZGcf/OQASCaTxGIxDMNA00P8iEbpuXyJ8Tw77+wWJhWZQYuVbiHoFIKwpmUC4XCYzc1NDMMgHo9z8+IFvl6/xsf7D9ArbjOpyAxLEt1C0CUErfvJDwBd14lEImxvb/N9fR1fgY3egmyWsq0sO/poUyw4pb3mLiFolyRM09wDEokEfr+fUChEJBJh4HgBS7kKn92zLIy9ZriqklFZwiEEHfsRRp1O0un0HpDa3cU9M8PKygp3Tp5AzbKgZlmYt1uYtkn02q0MyYKmnBxWNI27Nhtut5tkMrkHmKZJbWkpqqryQpFxKTJTisyEVeaVRWJIlqgpLuZRWRkejwe/34/P58ucwZvWVhYXF5l2uejIzeHGqbM4ZYmB/dy1hUV8mJpibm4On8/H1tbW4T1YXV3F6/WysLDA5Pg4nfsDe5yfz8OiIjweD5qmEQwGf7/KwWCQtbU1NE2jRZbpEoI2SWKqr49lVUXX9T/fAkAgEKC/e5SW6mo6hKD+zGn6e0bw+/x/PyaA9S/rvOwfobGukfpbddyraMDR7iCwHPg34H9KCCF+Abts3KCj/p6aAAAAAElFTkSuQmCC">LibrePlanet</A>
++ <DT><A HREF="https://www.h-node.org/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABgElEQVQ4jaXRz2uSARzHcb0vlRGEzTVWISU1BVkFYTIyjNK1pKcxHA+yhWMWIamHYikFgpoLIi9jwegi3QbL9SzdLmMbM9J+DkJBgm5RDvEPeHeQHOyQz0OH9+V7ePGBr0pqpPmfVPsP8a0AR4MnMEwf48x9K0s/E8oAY9iEMOvD+8yP2qVjrhhRBnSN61n5sIpULqC+pGHh8wNlgEY8jPQXcGh4VXukDND5evYAl46odIuXtYdKAANSudAChO52/XeMZMohecCbcoGdH99Y+7LO72adT9+/4nh8nYOjBl7/SsoB8gBkpHk8T0S2K++pN3fRin3cfnFDHvCuWkI9rEMvHGEo5gbAHnXhnLF1BpZLeRaLOVT2A8Q3A5wMngXgWtKLxX9KPqC+rCWQvYkpeK4NWKcGOgO50ts2MJJ0cPreeQDciTHMchZYIhcwh2wcuqjn+ccwGm9v6wsTxxn0dVgQXZ7Ek3Agpq6QrcaQGmmebtxFSDkRU1fJVmL/BpT2ByV/3eDMhinRAAAAAElFTkSuQmCC">h-node</A>
+ </DL><p>
+ </DL><p>
+diff --git a/browser/modules/AboutHome.jsm b/browser/modules/AboutHome.jsm
+index bcb7d1c..f902aac 100644
+--- a/browser/modules/AboutHome.jsm
++++ b/browser/modules/AboutHome.jsm
+@@ -8,7 +8,7 @@ var Cc = Components.classes;
+ var Ci = Components.interfaces;
+ var Cu = Components.utils;
+
+-this.EXPORTED_SYMBOLS = [ "AboutHomeUtils", "AboutHome" ];
++this.EXPORTED_SYMBOLS = [ "AboutHome" ];
+
+ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+ Components.utils.import("resource://gre/modules/Services.jsm");
+@@ -22,68 +22,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
+ XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+ "resource://gre/modules/Promise.jsm");
+
+-// Url to fetch snippets, in the urlFormatter service format.
+-const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
+-
+-// Should be bumped up if the snippets content format changes.
+-const STARTPAGE_VERSION = 4;
+-
+-this.AboutHomeUtils = {
+- get snippetsVersion() {
+- return STARTPAGE_VERSION;
+- },
+-
+- /*
+- * showKnowYourRights - Determines if the user should be shown the
+- * about:rights notification. The notification should *not* be shown if
+- * we've already shown the current version, or if the override pref says to
+- * never show it. The notification *should* be shown if it's never been seen
+- * before, if a newer version is available, or if the override pref says to
+- * always show it.
+- */
+- get showKnowYourRights() {
+- // Look for an unconditional override pref. If set, do what it says.
+- // (true --> never show, false --> always show)
+- try {
+- return !Services.prefs.getBoolPref("browser.rights.override");
+- } catch (e) { }
+- // Ditto, for the legacy EULA pref.
+- try {
+- return !Services.prefs.getBoolPref("browser.EULA.override");
+- } catch (e) { }
+-
+- if (!AppConstants.MOZILLA_OFFICIAL) {
+- // Non-official builds shouldn't show the notification.
+- return false;
+- }
+-
+- // Look to see if the user has seen the current version or not.
+- var currentVersion = Services.prefs.getIntPref("browser.rights.version");
+- try {
+- return !Services.prefs.getBoolPref("browser.rights." + currentVersion + ".shown");
+- } catch (e) { }
+-
+- // Legacy: If the user accepted a EULA, we won't annoy them with the
+- // equivalent about:rights page until the version changes.
+- try {
+- return !Services.prefs.getBoolPref("browser.EULA." + currentVersion + ".accepted");
+- } catch (e) { }
+-
+- // We haven't shown the notification before, so do so now.
+- return true;
+- }
+-};
+-
+-/**
+- * Returns the URL to fetch snippets from, in the urlFormatter service format.
+- */
+-XPCOMUtils.defineLazyGetter(AboutHomeUtils, "snippetsURL", function() {
+- let updateURL = Services.prefs
+- .getCharPref(SNIPPETS_URL_PREF)
+- .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
+- return Services.urlFormatter.formatURL(updateURL);
+-});
+-
+ /**
+ * This code provides services to the about:home page. Whenever
+ * about:home needs to do something chrome-privileged, it sends a
+@@ -162,17 +100,8 @@ var AboutHome = {
+ ss.promiseInitialized.then(function() {
+ let data = {
+ showRestoreLastSession: ss.canRestoreLastSession,
+- snippetsURL: AboutHomeUtils.snippetsURL,
+- showKnowYourRights: AboutHomeUtils.showKnowYourRights,
+- snippetsVersion: AboutHomeUtils.snippetsVersion,
+ };
+
+- if (AboutHomeUtils.showKnowYourRights) {
+- // Set pref to indicate we've shown the notification.
+- let currentVersion = Services.prefs.getIntPref("browser.rights.version");
+- Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
+- }
+-
+ if (target && target.messageManager) {
+ target.messageManager.sendAsyncMessage("AboutHome:Update", data);
+ } else {
diff --git a/libre/icecat/mozconfig b/libre/icecat/mozconfig
new file mode 100644
index 000000000..903b2add9
--- /dev/null
+++ b/libre/icecat/mozconfig
@@ -0,0 +1,48 @@
+. $topsrcdir/browser/config/mozconfig
+
+ac_add_options --prefix=/usr
+ac_add_options --libdir=/usr/lib
+ac_add_options --enable-release
+ac_add_options --enable-gold
+ac_add_options --enable-pie
+
+ac_add_options --enable-default-toolkit=cairo-gtk3
+
+# IceCat
+ac_add_options --enable-official-branding
+ac_add_options --with-distribution-id=org.gnu
+ac_add_options --with-app-basename=icecat
+ac_add_options --with-app-name=icecat
+
+# System libraries
+ac_add_options --with-system-nspr
+ac_add_options --with-system-nss
+ac_add_options --with-system-jpeg
+ac_add_options --with-system-zlib
+ac_add_options --with-system-bz2
+ac_add_options --with-system-png
+ac_add_options --with-system-libevent
+ac_add_options --with-system-libvpx
+ac_add_options --with-system-icu
+ac_add_options --enable-system-hunspell
+ac_add_options --enable-system-sqlite
+ac_add_options --enable-system-ffi
+# system cairo without layers acceleration results in choppy video playback
+#ac_add_options --enable-system-cairo
+ac_add_options --enable-system-pixman
+
+# Features
+ac_add_options --enable-startup-notification
+ac_add_options --enable-pulseaudio
+ac_add_options --disable-gstreamer
+
+ac_add_options --disable-crashreporter
+ac_add_options --disable-updater
+ac_add_options --disable-installer
+ac_add_options --disable-telemetry
+ac_add_options --disable-debug-symbols
+
+# Parabola features
+ac_add_options --disable-safe-browsing
+ac_add_options --disable-url-classifier
+ac_add_options --disable-eme
diff --git a/libre/icecat/mozilla-1228540-1.patch b/libre/icecat/mozilla-1228540-1.patch
new file mode 100644
index 000000000..be6ffc316
--- /dev/null
+++ b/libre/icecat/mozilla-1228540-1.patch
@@ -0,0 +1,84 @@
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1452675061 0
+# Wed Jan 13 08:51:01 2016 +0000
+# Node ID cf699e95e98829b465b64a7e0281d95ec851ce8c
+# Parent 3c9f357598e86c2f593e9895d5725bf3498f8f5a
+Bug 1228540 - pt 2 - Remove our HBGetGlyphHOrigin callback, as the default behavior is sufficient.
+
+diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp
+--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
++++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
+@@ -349,27 +349,16 @@ gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb
+ static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
+ // Currently, we don't offer gfxFont subclasses a method to override this
+ // and provide hinted platform-specific vertical advances (analogous to the
+ // GetGlyphWidth method for horizontal advances). If that proves necessary,
+ // we'll add a new gfxFont method and call it from here.
+ return fcd->mShaper->GetGlyphVAdvance(glyph);
+ }
+
+-/* static */
+-hb_bool_t
+-gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
+- hb_codepoint_t glyph,
+- hb_position_t *x, hb_position_t *y,
+- void *user_data)
+-{
+- // We work in horizontal coordinates, so no origin adjustment needed here.
+- return true;
+-}
+-
+ struct VORG {
+ AutoSwap_PRUint16 majorVersion;
+ AutoSwap_PRUint16 minorVersion;
+ AutoSwap_PRInt16 defaultVertOriginY;
+ AutoSwap_PRUint16 numVertOriginYMetrics;
+ };
+
+ struct VORGrec {
+@@ -1262,19 +1251,16 @@ gfxHarfBuzzShaper::Initialize()
+ hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
+ HBGetGlyphHAdvance,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs,
+ HBGetGlyphVAdvance,
+ nullptr, nullptr);
+- hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs,
+- HBGetGlyphHOrigin,
+- nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
+ HBGetGlyphVOrigin,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(sHBFontFuncs,
+ HBGetGlyphExtents,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs,
+ HBGetContourPoint,
+diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h
+--- a/gfx/thebes/gfxHarfBuzzShaper.h
++++ b/gfx/thebes/gfxHarfBuzzShaper.h
+@@ -56,21 +56,16 @@ public:
+ hb_codepoint_t glyph, void *user_data);
+
+ // get harfbuzz vertical advance in 16.16 fixed point format.
+ static hb_position_t
+ HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph, void *user_data);
+
+ static hb_bool_t
+- HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
+- hb_codepoint_t glyph,
+- hb_position_t *x, hb_position_t *y,
+- void *user_data);
+- static hb_bool_t
+ HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data);
+
+ hb_position_t GetHKerning(uint16_t aFirstGlyph,
+ uint16_t aSecondGlyph) const;
+
diff --git a/libre/icecat/no-libnotify.patch b/libre/icecat/no-libnotify.patch
new file mode 100644
index 000000000..8d5845743
--- /dev/null
+++ b/libre/icecat/no-libnotify.patch
@@ -0,0 +1,51 @@
+diff --git i/toolkit/system/gnome/moz.build w/toolkit/system/gnome/moz.build
+index 0ecde07..206d6eb 100644
+--- i/toolkit/system/gnome/moz.build
++++ w/toolkit/system/gnome/moz.build
+@@ -5,9 +5,7 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ SOURCES += [
+- 'nsAlertsIconListener.cpp',
+ 'nsGnomeModule.cpp',
+- 'nsSystemAlertsService.cpp',
+ ]
+
+ if CONFIG['MOZ_ENABLE_GCONF']:
+diff --git i/toolkit/system/gnome/nsGnomeModule.cpp w/toolkit/system/gnome/nsGnomeModule.cpp
+index 6ecebcc..2f193a3 100644
+--- i/toolkit/system/gnome/nsGnomeModule.cpp
++++ w/toolkit/system/gnome/nsGnomeModule.cpp
+@@ -20,8 +20,6 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsGIOService)
+ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGSettingsService, Init)
+ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPackageKitService, Init)
+ #endif
+-#include "nsSystemAlertsService.h"
+-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsSystemAlertsService, Init)
+
+ #ifdef MOZ_ENABLE_GCONF
+ NS_DEFINE_NAMED_CID(NS_GCONFSERVICE_CID);
+@@ -31,7 +29,6 @@ NS_DEFINE_NAMED_CID(NS_GIOSERVICE_CID);
+ NS_DEFINE_NAMED_CID(NS_GSETTINGSSERVICE_CID);
+ NS_DEFINE_NAMED_CID(NS_PACKAGEKITSERVICE_CID);
+ #endif
+-NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
+
+ static const mozilla::Module::CIDEntry kGnomeCIDs[] = {
+ #ifdef MOZ_ENABLE_GCONF
+@@ -42,7 +39,6 @@ static const mozilla::Module::CIDEntry kGnomeCIDs[] = {
+ { &kNS_GSETTINGSSERVICE_CID, false, nullptr, nsGSettingsServiceConstructor },
+ { &kNS_PACKAGEKITSERVICE_CID, false, nullptr, nsPackageKitServiceConstructor },
+ #endif
+- { &kNS_SYSTEMALERTSSERVICE_CID, false, nullptr, nsSystemAlertsServiceConstructor },
+ { nullptr }
+ };
+
+@@ -55,7 +51,6 @@ static const mozilla::Module::ContractIDEntry kGnomeContracts[] = {
+ { NS_GSETTINGSSERVICE_CONTRACTID, &kNS_GSETTINGSSERVICE_CID },
+ { NS_PACKAGEKITSERVICE_CONTRACTID, &kNS_PACKAGEKITSERVICE_CID },
+ #endif
+- { NS_SYSTEMALERTSERVICE_CONTRACTID, &kNS_SYSTEMALERTSSERVICE_CID },
+ { nullptr }
+ };
+
diff --git a/libre/icecat/remove-google-play-services-support.patch b/libre/icecat/remove-google-play-services-support.patch
new file mode 100644
index 000000000..f184b15ad
--- /dev/null
+++ b/libre/icecat/remove-google-play-services-support.patch
@@ -0,0 +1,64 @@
+diff -Nur a/configure b/configure
+--- a/configure 2015-08-23 17:05:16.000000000 -0300
++++ b/configure 2015-08-25 17:13:48.155780403 -0300
+@@ -18883,46 +18883,6 @@
+
+
+
+-if test -n "$MOZ_NATIVE_DEVICES" ; then
+-
+-
+- echo $ac_n "checking for google play services""... $ac_c" 1>&6
+-echo "configure:18891: checking for google play services" >&5
+- GOOGLE_PLAY_SERVICES_LIB="${ANDROID_SDK_ROOT}/extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar"
+- GOOGLE_PLAY_SERVICES_RES="${ANDROID_SDK_ROOT}/extras/google/google_play_services/libproject/google-play-services_lib/res"
+-
+-
+- if ! test -e $GOOGLE_PLAY_SERVICES_LIB ; then
+- { echo "configure: error: You must download Google Play Services to build with native video casting support enabled. Run the Android SDK tool and install Google Play Services under Extras. See http://developer.android.com/google/play-services/setup.html for more info. (looked for $GOOGLE_PLAY_SERVICES_LIB) " 1>&2; echo "configure: error: You must download Google Play Services to build with native video casting support enabled. Run the Android SDK tool and install Google Play Services under Extras. See http://developer.android.com/google/play-services/setup.html for more info. (looked for $GOOGLE_PLAY_SERVICES_LIB) " 1>&5; exit 1; }
+- fi
+- echo "$ac_t""$GOOGLE_PLAY_SERVICES_LIB" 1>&6
+-
+- ANDROID_APPCOMPAT_LIB="$ANDROID_COMPAT_DIR_BASE/v7/appcompat/libs/android-support-v7-appcompat.jar"
+- ANDROID_APPCOMPAT_RES="$ANDROID_COMPAT_DIR_BASE/v7/appcompat/res"
+- echo $ac_n "checking for v7 appcompat library""... $ac_c" 1>&6
+-echo "configure:18904: checking for v7 appcompat library" >&5
+- if ! test -e $ANDROID_APPCOMPAT_LIB ; then
+- { echo "configure: error: You must download the v7 app compat Android support library when targeting Android with native video casting support enabled. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_APPCOMPAT_LIB)" 1>&2; echo "configure: error: You must download the v7 app compat Android support library when targeting Android with native video casting support enabled. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_APPCOMPAT_LIB)" 1>&5; exit 1; }
+- fi
+- echo "$ac_t""$ANDROID_APPCOMPAT_LIB" 1>&6
+-
+-
+-
+- ANDROID_MEDIAROUTER_LIB="$ANDROID_COMPAT_DIR_BASE/v7/mediarouter/libs/android-support-v7-mediarouter.jar"
+- ANDROID_MEDIAROUTER_RES="$ANDROID_COMPAT_DIR_BASE/v7/mediarouter/res"
+- echo $ac_n "checking for v7 mediarouter library""... $ac_c" 1>&6
+-echo "configure:18915: checking for v7 mediarouter library" >&5
+- if ! test -e $ANDROID_MEDIAROUTER_LIB ; then
+- { echo "configure: error: You must download the v7 media router Android support library when targeting Android with native video casting support enabled. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_MEDIAROUTER_LIB)" 1>&2; echo "configure: error: You must download the v7 media router Android support library when targeting Android with native video casting support enabled. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_MEDIAROUTER_LIB)" 1>&5; exit 1; }
+- fi
+- echo "$ac_t""$ANDROID_MEDIAROUTER_LIB" 1>&6
+-
+-
+-fi
+-
+-
+-
+-
+ if test "$MOZ_ENABLE_GTK" -o "$MOZ_ENABLE_QT"
+ then
+ succeeded=no
+@@ -29180,13 +29140,6 @@
+ (''' MOZ_OFFICIAL_BRANDING ''', r''' $MOZ_OFFICIAL_BRANDING ''')
+ (''' MOZ_BRANDING_DIRECTORY ''', r''' $MOZ_BRANDING_DIRECTORY ''')
+ (''' MOZ_DISTRIBUTION_ID ''', r''' $MOZ_DISTRIBUTION_ID ''')
+- (''' MOZ_NATIVE_DEVICES ''', r''' $MOZ_NATIVE_DEVICES ''')
+- (''' GOOGLE_PLAY_SERVICES_LIB ''', r''' $GOOGLE_PLAY_SERVICES_LIB ''')
+- (''' GOOGLE_PLAY_SERVICES_RES ''', r''' $GOOGLE_PLAY_SERVICES_RES ''')
+- (''' ANDROID_APPCOMPAT_LIB ''', r''' $ANDROID_APPCOMPAT_LIB ''')
+- (''' ANDROID_APPCOMPAT_RES ''', r''' $ANDROID_APPCOMPAT_RES ''')
+- (''' ANDROID_MEDIAROUTER_LIB ''', r''' $ANDROID_MEDIAROUTER_LIB ''')
+- (''' ANDROID_MEDIAROUTER_RES ''', r''' $ANDROID_MEDIAROUTER_RES ''')
+ (''' _PANGOCHK_CFLAGS ''', list(r''' $_PANGOCHK_CFLAGS '''.split()))
+ (''' _PANGOCHK_LIBS ''', list(r''' $_PANGOCHK_LIBS '''.split()))
+ (''' MOZ_PANGO_CFLAGS ''', list(r''' $MOZ_PANGO_CFLAGS '''.split()))
diff --git a/libre/icecat/vendor.js b/libre/icecat/vendor.js
new file mode 100644
index 000000000..32fddb8db
--- /dev/null
+++ b/libre/icecat/vendor.js
@@ -0,0 +1,28 @@
+// Use LANG environment variable to choose locale
+pref("intl.locale.matchOS", true);
+
+// Disable default browser checking.
+pref("browser.shell.checkDefaultBrowser", false);
+
+// Don't disable our bundled extensions in the application directory
+pref("extensions.autoDisableScopes", 11);
+pref("extensions.shownSelectionUI", true);
+
+// Disable "alt" as a shortcut key to open full menu bar. Conflicts with "alt" as a modifier
+pref("ui.key.menuAccessKeyFocuses", false);
+
+// Make sure that Firefox Social stuff are empty
+pref("social.whitelist", "");
+pref("social.directories", "");
+
+// Disable the GeoLocation API for content
+pref("geo.enabled", false);
+
+// Make sure that the request URL of the GeoLocation backend is empty
+pref("geo.wifi.uri", "");
+
+// Disable the least secure encryption protocols
+pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", false);
+pref("security.ssl3.ecdhe_rsa_rc4_128_sha", false);
+pref("security.ssl3.rsa_rc4_128_md5", false);
+pref("security.ssl3.rsa_rc4_128_sha", false);