summaryrefslogtreecommitdiff
path: root/unmaintained
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-10-24 06:31:07 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-10-24 06:31:49 -0300
commite8907fab6658afc6681f1a40e28f058fa87f4575 (patch)
tree5d31c6b2df1393df4320a2dd5bb8d80ea22eeb60 /unmaintained
parent713bf090423e07809d39d2facdf61aefad1cebec (diff)
icecat: move package and its dependencies to [unmaintained] -> https://lists.parabola.nu/pipermail/dev/2016-October/004529.html
Diffstat (limited to 'unmaintained')
-rw-r--r--unmaintained/icecat-firebug/PKGBUILD28
-rw-r--r--unmaintained/icecat-l10n/PKGBUILD252
-rw-r--r--unmaintained/icecat-l10n/brand.dtd9
-rw-r--r--unmaintained/icecat-l10n/brand.properties16
-rw-r--r--unmaintained/icecat-l10n/browserconfig.properties6
-rw-r--r--unmaintained/icecat-l10n/region.properties26
-rw-r--r--unmaintained/icecat-noscript/PKGBUILD37
-rw-r--r--unmaintained/icecat-raismth/PKGBUILD28
-rw-r--r--unmaintained/icecat-spell-ru/PKGBUILD30
-rw-r--r--unmaintained/icecat-theme-gnome-tweak/PKGBUILD26
-rw-r--r--unmaintained/icecat-theme-gnome/PKGBUILD28
-rw-r--r--unmaintained/icecat-ublock-origin/PKGBUILD24
-rw-r--r--unmaintained/icecat-vimperator/PKGBUILD26
-rw-r--r--unmaintained/icecat/PKGBUILD193
-rw-r--r--unmaintained/icecat/disable-crypto-hardening-settings.patch54
-rw-r--r--unmaintained/icecat/disable-spoofSource-referer.patch26
-rw-r--r--unmaintained/icecat/firefox-gcc-6.0.patch26
-rw-r--r--unmaintained/icecat/gcc6-fix-compilation-for-IceCat.patch37
-rw-r--r--unmaintained/icecat/gnu_headshadow.pngbin0 -> 6785 bytes
-rw-r--r--unmaintained/icecat/harfbuzz-1.1.3.patch27038
-rw-r--r--unmaintained/icecat/icecat-fixed-loading-icon.pngbin0 -> 12184 bytes
-rw-r--r--unmaintained/icecat/icecat-install-dir.patch12
-rw-r--r--unmaintained/icecat/icecat.desktop352
-rw-r--r--unmaintained/icecat/icecat.install13
-rw-r--r--unmaintained/icecat/libre.patch890
-rw-r--r--unmaintained/icecat/mozconfig40
-rw-r--r--unmaintained/icecat/mozilla-1228540-1.patch84
-rw-r--r--unmaintained/icecat/remove-google-play-services-support.patch64
-rw-r--r--unmaintained/icecat/vendor.js28
29 files changed, 29393 insertions, 0 deletions
diff --git a/unmaintained/icecat-firebug/PKGBUILD b/unmaintained/icecat-firebug/PKGBUILD
new file mode 100644
index 000000000..b9eb8be0b
--- /dev/null
+++ b/unmaintained/icecat-firebug/PKGBUILD
@@ -0,0 +1,28 @@
+# $Id: PKGBUILD 129379 2015-03-16 17:25:46Z speps $
+# Maintainer (Arch): speps <speps at aur dot archlinux dot org>
+
+pkgname=icecat-firebug
+pkgver=2.0.8
+pkgrel=1
+pkgdesc="IceCat extension with tools for web development."
+arch=(any)
+url="http://getfirebug.com/"
+license=('custom:BSD')
+groups=('icecat-addons')
+depends=('icecat')
+provides=('firebug')
+source=("${url}releases/firebug/${pkgver%.*}/firebug-$pkgver.xpi")
+md5sums=('de60ceef13c3d17d2f6ce4f68acc367b')
+
+package() {
+ # extension
+ _dest="$pkgdir/usr/lib/icecat/browser/extensions/firebug@software.joehewitt.com"
+ find . -type d -exec install -d {} $_dest/{} \;
+ find . -type f -exec install -Dm644 {} $_dest/{} \;
+
+ # license
+ install -Dm644 license.txt \
+ "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/unmaintained/icecat-l10n/PKGBUILD b/unmaintained/icecat-l10n/PKGBUILD
new file mode 100644
index 000000000..f545cec4d
--- /dev/null
+++ b/unmaintained/icecat-l10n/PKGBUILD
@@ -0,0 +1,252 @@
+# Maintainer: Márcio Silva <coadde@parabola.nu>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+# Contributor: Luke Shumaker <lukeshu@sbcglobal.net>
+# Contributor: fauno <fauno@kiwwwi.com.ar>
+# Contributor: Figue <ffigue@gmail.com>
+
+_pkgbase=icecat
+pkgbase=$_pkgbase-l10n
+_pkgver=38.8.0-gnu2
+pkgver=38.8.0_gnu2
+pkgrel=1
+pkgdesc="Language pack for GNU IceCat."
+arch=('any')
+url="http://www.gnu.org/software/gnuzilla/"
+license=('MPL' 'GPL')
+depends=("$_pkgbase=$pkgver")
+makedepends=('unzip' 'zip')
+
+_languages=(
+ 'ach "Acholi"'
+ 'af "Afrikaans"'
+ 'an "Aragonese"'
+ 'ar "Arabic"'
+ 'as "Assamese"'
+ 'ast "Asturian"'
+ 'az "Azerbaijani"'
+ 'be "Belarusian"'
+ 'bg "Bulgarian"'
+ 'bn-BD "Bengali (Bangladesh)"'
+ 'bn-IN "Bengali (India)"'
+ 'br "Breton"'
+ 'bs "Bosnian"'
+ 'ca "Catalan"'
+ 'cs "Czech"'
+ 'cy "Welsh"'
+ 'da "Danish"'
+ 'de "German"'
+ 'dsb "Lower Sorbian"'
+ 'el "Greek"'
+ 'en-GB "English (British)"'
+# 'en-US "English (US)"'
+ 'en-ZA "English (South African)"'
+ 'eo "Esperanto"'
+ 'es-AR "Spanish (Argentina)"'
+ 'es-CL "Spanish (Chile)"'
+ 'es-ES "Spanish (Spain)"'
+ 'es-MX "Spanish (Mexico)"'
+ 'et "Estonian"'
+ 'eu "Basque"'
+ 'fa "Persian"'
+ 'ff "Fulah"'
+ 'fi "Finnish"'
+ 'fr "French"'
+ 'fy-NL "Frisian"'
+ 'ga-IE "Irish"'
+ 'gd "Gaelic (Scotland)"'
+ 'gl "Galician"'
+ 'gu-IN "Gujarati (India)"'
+ 'he "Hebrew"'
+ 'hi-IN "Hindi (India)"'
+ 'hr "Croatian"'
+ 'hsb "Upper Sorbian"'
+ 'hu "Hungarian"'
+ 'hy-AM "Armenian"'
+ 'id "Indonesian"'
+ 'is "Icelandic"'
+ 'it "Italian"'
+ 'ja "Japanese"'
+ 'kk "Kazakh"'
+ 'km "Khmer"'
+ 'kn "Kannada"'
+ 'ko "Korean"'
+ 'lij "Ligurian"'
+ 'lt "Lithuanian"'
+ 'lv "Latvian"'
+ 'mai "Maithili"'
+ 'mk "Macedonian"'
+ 'ml "Malayalam"'
+ 'mr "Marathi"'
+ 'ms "Malay"'
+ 'nb-NO "Norwegian (Bokmål)"'
+ 'nl "Dutch"'
+ 'nn-NO "Norwegian (Nynorsk)"'
+ 'or "Oriya"'
+ 'pa-IN "Punjabi (India)"'
+ 'pl "Polish"'
+ 'pt-BR "Portuguese (Brazilian)"'
+ 'pt-PT "Portuguese (Portugal)"'
+ 'rm "Romansh"'
+ 'ro "Romanian"'
+ 'ru "Russian"'
+ 'si "Sinhala"'
+ 'sk "Slovak"'
+ 'sl "Slovenian"'
+ 'son "Songhai"'
+ 'sq "Albanian"'
+ 'sr "Serbian"'
+ 'sv-SE "Swedish"'
+ 'ta "Tamil"'
+ 'te "Telugu"'
+ 'th "Thai"'
+ 'tr "Turkish"'
+ 'uk "Ukrainian"'
+ 'uz "Uzbek"'
+ 'vi "Vietnamese"'
+ 'xh "Xhosa"'
+ 'zh-CN "Chinese (Simplified)"'
+ 'zh-TW "Chinese (Traditional)"'
+)
+
+pkgname=()
+source=('region.properties')
+_url=http://ftp.gnu.org/gnu/gnuzilla/$_pkgver/langpacks
+#_url=http://jenkins.trisquel.info/$_pkgbase/binaries/langpacks
+
+#source=('brand.dtd' 'brand.properties' 'browserconfig.properties' 'region.properties')
+#_url=http://download.cdn.mozilla.net/pub/firefox/releases/${_pkgver}esr/linux-i686/xpi
+
+for _lang in "${_languages[@]}"; do
+ _locale=${_lang%% *}
+ _pkgname=$pkgbase-${_locale,,}
+
+ pkgname+=($_pkgname)
+ source+=("$_url/$_pkgbase-${_pkgver%-*}.$_locale.langpack.xpi")
+# source+=("$_pkgbase-$_pkgver.$_locale.langpack.xpi::$_url/$_locale.xpi")
+ eval "package_$_pkgname() {
+ _package $_lang
+ }"
+done
+
+# Don't extract anything
+noextract=(${source[@]%%::*})
+
+_package() {
+ pkgdesc="$2 language pack for GNU IceCat."
+ replaces=(icecat-i18n-${1,,})
+ conflicts=(icecat-i18n-${1,,})
+
+ unzip icecat-${_pkgver%-*}.$1.langpack.xpi -d $1
+ rm -v icecat-${_pkgver%-*}.$1.langpack.xpi
+# install -vDm644 $srcdir/brand.dtd $1/browser/chrome/$1/locale/branding/
+# install -vDm644 $srcdir/brand.properties $1/browser/chrome/$1/locale/branding/
+# install -vDm644 $srcdir/browserconfig.properties $1/browser/chrome/$1/locale/branding/
+# mv $1/browser/defaults/preferences/{firefox,icecat}-l10n.js
+# sed -i '\|firefox-l10n|d' $1/browser/defaults/preferences/icecat-l10n.js
+ install -vDm644 $srcdir/region.properties $1/browser/chrome/$1/locale/browser-region
+# sed -i 's|Firefox|IceCat|
+# ' $1/browser/chrome/$1/locale/browser/devtools/sourceeditor.properties \
+# $1/browser/chrome/$1/locale/browser/devtools/toolbox.dtd \
+# $1/browser/chrome/$1/locale/browser/devtools/webide.dtd \
+# $1/browser/chrome/$1/locale/browser/devtools/webide.properties
+ rm -rv $1/{browser/{chrome/.mkdir.done,searchplugins},chrome/{.mkdir.done,$1/locale/$1/global-platform/{mac,win}}}
+# sed -i -e 's/firefox/icecat/' $1/install.rdf
+ cd $1
+ zip -r langpack-$1@icecat.mozilla.org.xpi .
+ mv -v langpack-$1@icecat.mozilla.org.xpi $srcdir
+ cd ..
+ rm -rv $1
+
+ install -vDm644 langpack-$1@icecat.mozilla.org.xpi \
+ "$pkgdir/usr/lib/icecat/browser/extensions/langpack-$1@icecat.mozilla.org.xpi"
+}
+
+sha256sums=('fc301f3ce1f7d7cd995c7920af18f638e7dd40ade90318567c2bdb922d9cd11a'
+ '7bbdb563b020c04d2510360f3c1eea929a3cfb6bf0e76dd3e93ab0429815a810'
+ '4ffcf9c070db6e8790c2f8fd216b79710e11d9b5bcda81364fccfd596e8ac3a2'
+ 'e8a9aff1f5f7992ed94b299224398dd0883b68e730e914d3aa9ce5e503096112'
+ '5f7c63c16aa2c64bd82f4407cf07fab7f1951c1a8040dd9af1d107079161682c'
+ 'f036744ff3b4c9ae59695040db1c004b26698b82019e3c74f48a98ca6b4d3215'
+ '4c4db2e6bd239dcf7da0d3fa42ff8c6c2af7036c7a07f736cb2f8327ea9b8380'
+ '5e68099926beac0b17223bd6b37f76a77c642fdb13a029583897fbbc5f46bd65'
+ '4c60013df47f4ce0786cd6db6f2dffc620a350c3420f3e9e5be285ec40b0a066'
+ 'e0ce35cdf5f863556d6a043012621d42f2a0fa979dc6548e3c761c360fb03804'
+ 'cf65fe00e3ead3db5c28abe068fedf3069a511ca6f41a14e6153b7f140dacbdf'
+ '52e0b834668f2e0fe6cee3301ba4daef8ea877816d7f801191fbddd8878ff39b'
+ 'b90a1c4ee0355a4b854cb0f12bfcbb4367aa3339b67a216832cdb13c0bdd1ccb'
+ '1db2efa07aab91609e570b6fd1e1287d800b0b71e033d182fc34527b8be3c402'
+ 'b5ad910c385d36996832c4b6ab605b87a6bcb51ec719feab3e3a3b0b340207d1'
+ '396019b64c46dd8077588af8c71b0e5ba496d2243e083aea470adce90fbacd27'
+ '77954203868f598cc6e43ec6ab629f466be4f017e9f89870bf3eafb09fa7a85d'
+ '313d56d69105b77af6a9d399e188946e1a3ce44e7ee5f55d37ea96d25c07a253'
+ 'e25ed244b96c49c9eeb5b39583f35e822facf9efb9becc6ce5257551431da783'
+ '4455d4eb58b899144b2946a6a8344e4419645b8c4c495e37eb8719efcaebff2b'
+ 'dbd3148deddb813455fbccee50bcc175b2cb40cb717900a5f44c77c1c2682c29'
+ '706a9a593a69947b0e3882b4f7028be1f6a0b4dd00e92082e321ea0bb3a0e6f8'
+ '9e5e68912f028a662b38076bb871675d10f079cdae9ad2aca65df465f45e0cfb'
+ '722cfa3ba7c806cc82185d639b9abbd735860d9a7571b2186468ee9e4031e33c'
+ '310f6b9e468c7b8e7702ef23766b532817a7982181facc3eaa33ec162755930e'
+ 'fd3af6ce224046db1feae88f7705041376bebccc9c2a4122f3ae9bbe8a092e79'
+ '382b83831ba6399ab79a593c096c59b941e48a06f7ce2754e5984a18e03b011f'
+ '354ce1cb88ea3ab4081b991aea5c522b229b7a9a5dc0d038132a4a033da5f036'
+ 'e9ab7fe608f6dd34f6123a7af921237b09c769eef23b610bb52332216d39e7ff'
+ '55518283aabaf32cd7aa34f81f356ec173b6c196455f4c91423ec999210ca41b'
+ '4ef6c0667c42db2ab052a6a15e3f65726960a07f90c83a20252013ea5f5b851d'
+ '4f91680c499687ed2144c619208cb7fde5c44a3b1a17e8db9dc945c7ff6b2dea'
+ 'c93378a18c66b84aa62a6575a6a189b5de1880888221021daab3372978eac769'
+ '8391a7c79574d0a7fa0d0416fb3274de12df7c8ada38c3c06a94a9b1ef295925'
+ '9c612fcaa8a124c075a6834ede683f791c49735426b80442ae159722ef978e08'
+ '3021caf567ad827878c36d4836cfc8880f8f06cfdf13c299928c878d6134064a'
+ '382f4766be734876734a614f52d429605f3ca0e6fe6d327ff49e9ecfb829483a'
+ 'd936bf868959618f21943b633fbbe3b92b9065a9823a9c1d2d889d46128cf8c3'
+ 'e2f01a06d9e7e4525e504d2bba3e8ca50a636a2ff4b12ff3ef553c7d9b22b67f'
+ '0583888b736a73dc761ea701004012ea05a80888172e0c5c9f295b9e6526117c'
+ '6929cd21f66acc07b0f8ff699c21706e11624ab2c0fc563dbb5d34ede28062ef'
+ '244718b422d8f0277bd335a5700e4d9ccf1ba8a681046379cd31068d8919555e'
+ '7edb712e1a21894317b30304b0a595ab8e77d881c9e1a8838a1e12f6fad71d0d'
+ 'e34fce031408b49912abb25d7aec21d89a95226987ee1db82036c524153d7185'
+ 'd162f4b18420330a35bd7be462427d94a6df4e3b81bde7782f76b07639e4e79e'
+ '9f89a0490a0eb37be9ffd15c7f896d9fa8f72d4cfb168feaecb0552735d7328f'
+ 'bba1056e3984c2bcf09c84de87e7bd4eaf848f619dbcd4133fdaef70bfc2ff85'
+ 'f813f9494fc8799c419d038215d7a69e5e01f913d4cccfc3c7cf96f999d61b6d'
+ 'f42642770076a2c513680444116861941ccb3353d6073493f03594b559401d8b'
+ 'd0eac65b19b343429eb632fc9de29ba5c3dbd7fc57df8018538eabd9e000de3f'
+ '5b575464dec0d94d7fef36213ce3a7c800d91c86df8f908607f4a6a1cfd708d2'
+ '77adce770612434e28eca4f375fac7417b885340506a20d7fd9372e5f8b2372b'
+ '67635e30dbfdce0594f74d33e3200abe1ab7479287a6b7edf05dba040fabc96c'
+ '0a31ef84ed08ec327cb79d6341cd59728d305c2b081109f07221a0066ac17e12'
+ 'b59b667d3805b45043f58cee2fee5af2d6e77ad13643af1c41860a26480b4b1c'
+ '034c6308f33c0cc4463f8e9e6bd46c10b0c8bd14c3ea3420e02fb3ff37233bc2'
+ '58e032e9a66fcb0be46808f2af09c5c3a1d291e0e9375a0db4edd68977b03722'
+ '77fa69364e360dcef549dfdebc3fe7ed3e8f21f331b4c04d28deeac5c5ecb746'
+ '3458db2d80be37712b0f3eb66372e267cc6a504a0ca7cf78ff532d0d94934ac5'
+ '1b4400a464f8c9731ec905dcaa362b28d61cca1d9dbc8ffe213f794faa904702'
+ '049df19cbae31c0d1f5f470a0d2c5d0b4bcfa383a178360bbeccadd3c1eaadcb'
+ '32b2be415addc07d3a3c2abd0fa6eab49cdd754af0eeca9e95af963abb3f1e00'
+ '4261c5d205b6266b9322d279be310df2d68c3efc9cf24de05a5c42888ea9d9a8'
+ 'cd746b2c0f63cdeff1d5b793a933c5b1858d3bd59fb79a2207350081a750927d'
+ '2d20ac7ab065c93362d26cce2c0836294434648f4ee487e1a767cbd9d8e6cd82'
+ 'c2a17180247c1f7084ef686f3f6f2d671a77e219fedaf6f60e87fae61ea7d132'
+ 'b8ce44940c958a46d0be32f27837dd69c326690582efaa6141e3da2e5cda9f8f'
+ 'c621c99b0f18a5018da46d7d3ad146e5fa1d436312bb6c4b9538d3d82e295554'
+ 'e71bfcc4136d112d5fcafeadb5cec080b62932d5d212f95f1bdceb952658b68b'
+ '17df86e5a32ac17b75e0a29497c6412f752e31299eb0532861e624cdf8dbf4c6'
+ 'bcebfdae249e51cd1ed3d305e6deb771ca4e4d9af186afb9080228b1241f18f5'
+ '82e70d54f5c8022d0e3e145f59f306025d1f47d50ad21ab2d6b0f9be7cd6ae97'
+ '7543bd6d0380276242fa7064ede5bd3730b0505340e10bca8608d0fd0d7e9bdc'
+ '588402bbae391b2998af38e1b01086706ba30461186f2dae8a3e2bbcec54e499'
+ 'ae12aa8022e2a8f9d89e5c097b2976f460e4a022ce3fe7877ec55bc86da9ab9c'
+ '6015c006c8e880177b59f1da1323753e52ef9068e5d11d9be7e04d22aba23567'
+ 'e249109618c7c9ec0525aa4fddb76681b90b3bb2184b06510188631be406da57'
+ '137cfec14508b4a09bdd4858ada6e74a032107b8631ee945585ee217bcd274e5'
+ '843e56d55ce5bb4a2e17bb2498487f48f7de54a2b5c45aa7601b6c821cc4c74b'
+ 'a101549c2524639d952b89a5b21b242f09ae27b33898ff8bf70ea5edc4539e69'
+ '3c7118834f913f29e14685f6c119b9fede1c7bff3ffefa2c4ef2f4aeaebf392a'
+ 'e9baf3219ba2ade8583f645497c2588407fccdeaa9edec2e02e55f029accf78d'
+ '44fddc2056cd2c78e9f1d15632266fa81828fb705501f6909e18557321a8f14e'
+ '3b1d08183ccff6886e71dcff551a48bae1fffa1502a0e77ead28605c752ff1df'
+ '8841a133f6ecdb218e07be154ef5ad904f88333904acd3bcc389f6c3e72514b8'
+ '056134453003abcc6305709b7b9ecebe2015721e144bd9ae6a86545aba90eafa'
+ '70452dd27e3f44663fe13e4046b0529d8e6211ea3b643e59ac296fe0c7550f11'
+ 'b6df7e9a0d74b99be41df3aa61d54b74fae04be51b8339136e88b071aefa426d'
+ 'ca4a3d24b694854588ac5e6dade7e47d01d061d6342c95d36c6a2ba2332d6993')
diff --git a/unmaintained/icecat-l10n/brand.dtd b/unmaintained/icecat-l10n/brand.dtd
new file mode 100644
index 000000000..ff4f95957
--- /dev/null
+++ b/unmaintained/icecat-l10n/brand.dtd
@@ -0,0 +1,9 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!ENTITY brandShorterName "IceCat">
+<!ENTITY brandShortName "IceCat">
+<!ENTITY brandFullName "GNU IceCat">
+<!ENTITY vendorShortName "GNU">
+<!ENTITY trademarkInfo.part1 "">
diff --git a/unmaintained/icecat-l10n/brand.properties b/unmaintained/icecat-l10n/brand.properties
new file mode 100644
index 000000000..4b4a4651c
--- /dev/null
+++ b/unmaintained/icecat-l10n/brand.properties
@@ -0,0 +1,16 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+brandShorterName=IceCat
+brandShortName=IceCat
+brandFullName=GNU IceCat
+vendorShortName=GNU
+
+homePageSingleStartMain=IceCat Start, a fast home page with built-in search
+homePageImport=Import your home page from %S
+
+homePageMigrationPageTitle=Home Page Selection
+homePageMigrationDescription=Please select the home page you wish to use:
+
+syncBrandShortName=Sync
diff --git a/unmaintained/icecat-l10n/browserconfig.properties b/unmaintained/icecat-l10n/browserconfig.properties
new file mode 100644
index 000000000..72ab4bed3
--- /dev/null
+++ b/unmaintained/icecat-l10n/browserconfig.properties
@@ -0,0 +1,6 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Do NOT localize or otherwise change these values
+browser.startup.homepage=about:icecat
diff --git a/unmaintained/icecat-l10n/region.properties b/unmaintained/icecat-l10n/region.properties
new file mode 100644
index 000000000..3333c1b71
--- /dev/null
+++ b/unmaintained/icecat-l10n/region.properties
@@ -0,0 +1,26 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Default search engine
+browser.search.defaultenginename=searx
+
+# Search engine order (order displayed in the search bar dropdown)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
+# profile database. Note that "new" is defined as "has a different URL"; this
+# means that it's not possible to update the name of existing handler, so
+# don't make any spelling errors here.
+gecko.handlerService.defaultHandlersVersion=4
+
+# The default set of protocol handlers for irc:
+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=Freenode Web IRC
+gecko.handlerService.schemes.ircs.0.uriTemplate=https://webchat.freenode.net
diff --git a/unmaintained/icecat-noscript/PKGBUILD b/unmaintained/icecat-noscript/PKGBUILD
new file mode 100644
index 000000000..4d6363045
--- /dev/null
+++ b/unmaintained/icecat-noscript/PKGBUILD
@@ -0,0 +1,37 @@
+# $Id: PKGBUILD 186197 2016-08-09 13:37:12Z spupykin $
+# Maintainer (Arch): Sergej Pupykin <pupykin.s+arch@gmail.com>
+# Contributor (Arch): Eschwartz <eschwartz93@gmail.com>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+
+pkgname=icecat-noscript
+pkgver=2.9.0.14
+pkgrel=1
+pkgdesc="Extension for icecat which disables script"
+arch=('any')
+url="http://noscript.net/"
+license=('GPL2')
+groups=('icecat-addons')
+depends=('icecat')
+makedepends=('unzip')
+source=(https://secure.informaction.com/download/releases/noscript-${pkgver}.xpi)
+noextract=("noscript-${pkgver}.xpi")
+md5sums=('e60590e188d0d2f69cbec5c6382f15fd')
+
+prepare() {
+ cd "${srcdir}"
+ unzip -qqo "noscript-${pkgver}.xpi" -d "noscript-${pkgver}"
+}
+
+package() {
+ cd "${srcdir}"
+
+ _extension_id="$(sed -n '/.*<em:id>\(.*\)<\/em:id>.*/{s//\1/p;q}' noscript-${pkgver}/install.rdf)"
+ _extension_dest="${pkgdir}/usr/lib/icecat/browser/extensions/${_extension_id}"
+ if grep '<em:unpack>true</em:unpack>' noscript-${pkgver}/install.rdf > /dev/null; then
+ install -dm755 "${_extension_dest}"
+ cp -R noscript-${pkgver}/* "${_extension_dest}"
+ chmod -R ugo+rX "${_extension_dest}"
+ else
+ install -Dm644 noscript-${pkgver}.xpi "${_extension_dest}.xpi"
+ fi
+}
diff --git a/unmaintained/icecat-raismth/PKGBUILD b/unmaintained/icecat-raismth/PKGBUILD
new file mode 100644
index 000000000..1bdd66289
--- /dev/null
+++ b/unmaintained/icecat-raismth/PKGBUILD
@@ -0,0 +1,28 @@
+# $Id: PKGBUILD 101450 2013-11-25 21:16:28Z speps $
+# Maintainer (Arch): speps <speps at aur dot archlinux dot org>
+
+pkgname=icecat-raismth
+pkgver=4.0.1
+pkgrel=1.2
+pkgdesc="IceCat plugin for watching Rai.tv live channels, vod and replay contents w/o *light (Silverlight/Moonlight)"
+arch=('any')
+url="http://acab.servebeer.com/"
+license=('GPL3')
+groups=('icecat-addons')
+depends=('icecat')
+optdepends=('mplayer: default video player'
+ 'faad: default audio player')
+provides=('raismth')
+source=("${url}raismth-$pkgver.xpi")
+md5sums=('f772ef1a74b0aba3a739849fee3238ea')
+
+package() {
+ cd "$srcdir"
+
+ # extension
+ _dest="$pkgdir/usr/lib/icecat/browser/extensions/raismth@mitm.rc"
+ find . -type d -exec install -d {} $_dest/{} \;
+ find . -type f -exec install -Dm644 {} $_dest/{} \;
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/unmaintained/icecat-spell-ru/PKGBUILD b/unmaintained/icecat-spell-ru/PKGBUILD
new file mode 100644
index 000000000..a58c1d3b9
--- /dev/null
+++ b/unmaintained/icecat-spell-ru/PKGBUILD
@@ -0,0 +1,30 @@
+# $Id: PKGBUILD 129457 2015-03-18 10:50:28Z spupykin $
+# Maintainer (Arch): Sergej Pupykin <pupykin.s+arch@gmail.com>
+# Contributor (Arch): Maciej Sitarz <macieks@freesco.pl>
+
+pkgname=icecat-spell-ru
+pkgver=0.4.5
+pkgrel=1
+pkgdesc="Russian spellchecker dictionary for IceCat"
+arch=(any)
+url="https://addons.mozilla.org/firefox/dictionaries/"
+license=("GPL")
+depends=("icecat")
+#noextract=(addon-$pkgver-an+fx+tb+fn+sm.xpi)
+source=(https://addons.cdn.mozilla.net/user-media/addons/3703/addon-$pkgver-an+fx+tb+fn+sm.xpi)
+md5sums=('05dbd25d73e3e4187ec51517658fcf69')
+
+package() {
+# _ffver=`pacman -Q icecat | cut -f2 -d\ | cut -f1 -d-`
+# depends=("icecat>=${_ffver}" "icecat<=${_ffver/0/99}")
+
+ cd $srcdir
+ rm $srcdir/*.xpi
+ local _dir=$pkgdir/usr/lib/icecat/browser/extensions/ru@dictionaries.addons.mozilla.org
+ mkdir -p "${_dir}"
+ cd "${_dir}"
+ sed -i 's#<em:maxVersion>.*</em:maxVersion>#<em:maxVersion>20.*</em:maxVersion>#' $srcdir/install.rdf
+ cp -r $srcdir/* "${_dir}"
+ find ${_dir} -type f -exec chmod 0644 {} \;
+ touch ${_dir}/chrome.manifest
+}
diff --git a/unmaintained/icecat-theme-gnome-tweak/PKGBUILD b/unmaintained/icecat-theme-gnome-tweak/PKGBUILD
new file mode 100644
index 000000000..4992bd490
--- /dev/null
+++ b/unmaintained/icecat-theme-gnome-tweak/PKGBUILD
@@ -0,0 +1,26 @@
+# $Id: PKGBUILD 171820 2016-04-25 17:37:34Z muflone $
+# Maintainer (Arch): Muflone http://www.muflone.com/contacts/english/
+# Maintainer: Omar Vega Ramos <ovruni@gnu.org.pe>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+# Contributor: Daniel Milewski <niitotantei@riseup.net>
+# Contributor: Isaac David <isacdaavid () isacdaavid!info>
+
+pkgname=icecat-theme-gnome-tweak
+_pkgname=firefox-gnome
+pkgver=38.1
+pkgrel=1
+pkgdesc="IceCat extension for customizing the GNOME 3 theme"
+url="https://addons.mozilla.org/en-us/firefox/addon/gnome-theme-tweak/"
+arch=('any')
+license=('MPL')
+depends=("icecat-theme-gnome")
+replaces=('icecat-theme-adwaita')
+conflicts=('icecat-theme-adwaita')
+source=("https://addons.cdn.mozilla.net/user-media/addons/458932/gnome_theme_tweak-${pkgver}-fx-linux.xpi")
+sha256sums=('cc664a1e80b587753ed9050495dafff685bfcd41c57cb81ab617fa960a4d6839')
+
+package() {
+ install -m 755 -d "${pkgdir}/usr/lib/icecat/browser/extensions"
+ _emid=$(sed -n '/.*<em:id>\(.*\)<\/em:id>.*/{s//\1/p;q}' install.rdf)
+ install -m 644 "gnome_theme_tweak-${pkgver}-fx-linux.xpi" "${pkgdir}/usr/lib/icecat/browser/extensions/${_emid}.xpi"
+}
diff --git a/unmaintained/icecat-theme-gnome/PKGBUILD b/unmaintained/icecat-theme-gnome/PKGBUILD
new file mode 100644
index 000000000..7d5e67284
--- /dev/null
+++ b/unmaintained/icecat-theme-gnome/PKGBUILD
@@ -0,0 +1,28 @@
+# $Id: PKGBUILD 171810 2016-04-25 17:30:31Z muflone $
+# Maintainer (Arch): Muflone http://www.muflone.com/contacts/english/
+# Contributor (Arch): Diego Principe <cdprincipe@at@gmail@dot@com>
+# Maintainer: Omar Vega Ramos <ovruni@gnu.org.pe>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+# Contributor: Daniel Milewski <niitotantei@riseup.net>
+# Contributor: Isaac David <isacdaavid () isacdaavid!info>
+
+pkgname=icecat-theme-gnome
+_pkgname=firefox-gnome
+pkgver=38.1
+pkgrel=1
+pkgdesc='GNOME 3 theme for IceCat (Previously known as "Adwaita")'
+url="https://addons.mozilla.org/en-us/firefox/addon/adwaita/"
+arch=('any')
+license=('MPL')
+depends=("icecat")
+replaces=('icecat-theme-adwaita')
+conflicts=('icecat-theme-adwaita')
+optdepends=('icecat-theme-gnome-tweak: GNOME theme customization')
+source=("https://addons.mozilla.org/firefox/downloads/file/410922/gnome_3-${pkgver}-fx-linux.xpi")
+sha256sums=('d230a3cc20739696281d7bb5aa5bb395afce782d53a97ab5270278602e4cb274')
+
+package() {
+ install -m 755 -d "${pkgdir}/usr/lib/icecat/browser/extensions"
+ _emid=$(sed -n '/.*<em:id>\(.*\)<\/em:id>.*/{s//\1/p;q}' install.rdf)
+ install -m 644 "gnome_3-${pkgver}-fx-linux.xpi" "${pkgdir}/usr/lib/icecat/browser/extensions/${_emid}.xpi"
+}
diff --git a/unmaintained/icecat-ublock-origin/PKGBUILD b/unmaintained/icecat-ublock-origin/PKGBUILD
new file mode 100644
index 000000000..702b62cda
--- /dev/null
+++ b/unmaintained/icecat-ublock-origin/PKGBUILD
@@ -0,0 +1,24 @@
+# Maintainer (Arch): Daniel M. Capella <polyzen@archlinux.info>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+
+pkgname=icecat-ublock-origin
+pkgver=1.9.12
+pkgrel=1
+pkgdesc='An efficient blocker add-on for various browsers. Fast, potent, and lean.'
+url=https://github.com/gorhill/uBlock
+arch=('any')
+license=('GPL3')
+depends=('icecat')
+provides=('icecat-adblock-plus')
+conflicts=('icecat-adblock-plus')
+replaces=('icecat-adblock-plus')
+groups=('icecat-addons')
+source=("https://addons.cdn.mozilla.net/user-media/addons/607454/ublock_origin-$pkgver-tb+an+fx+sm.xpi")
+noextract=("${source##*/}")
+sha512sums=('0901bb47317888dc7823b5d7841ff089ce757fab3fef895e34ea5138b38ca5190e5055dae569022ae6350dd69de36739235df5d46c2aaef3cf0c6675b656c9ec')
+
+package() {
+ install -Dm755 "${source##*/}" "$pkgdir"/usr/lib/icecat/browser/extensions/uBlock0@raymondhill.net.xpi
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/unmaintained/icecat-vimperator/PKGBUILD b/unmaintained/icecat-vimperator/PKGBUILD
new file mode 100644
index 000000000..d7a23f1f0
--- /dev/null
+++ b/unmaintained/icecat-vimperator/PKGBUILD
@@ -0,0 +1,26 @@
+# Maintainer (Arch): John Jenkins twodopeshaggy@gmail.com
+# Contributor (Arch): Gustavo Dutra <mechamo@gustavodutra.com>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+
+_pkgname=vimperator
+pkgname=icecat-vimperator
+license=("MIT")
+pkgver=3.9
+pkgrel=2
+pkgdesc="Make icecat look and behave like Vim"
+arch=('any')
+url="http://vimperator.org/vimperator"
+depends=('icecat')
+_extensionId="vimperator@mozdev.org"
+_fileName=vimperator-$pkgver.xpi
+source=(https://github.com/vimperator/vimperator-labs/releases/download/$_pkgname-$pkgver/$_pkgname-$pkgver.xpi)
+md5sums=('11449e9ed1a8e3fccf38a7570a700dd5')
+conflicts=('vimperator-hg' 'vimperator-git')
+
+package() {
+ cd $srcdir || return 1
+ local dstdir=$pkgdir/usr/lib/icecat/browser/extensions/$_extensionId
+ install -d $dstdir || return 1
+ cp -R * $dstdir || return 1
+ rm $dstdir/$_fileName
+}
diff --git a/unmaintained/icecat/PKGBUILD b/unmaintained/icecat/PKGBUILD
new file mode 100644
index 000000000..e44a520db
--- /dev/null
+++ b/unmaintained/icecat/PKGBUILD
@@ -0,0 +1,193 @@
+# 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=true
+
+pkgname=icecat
+_pkgver=38.8.0-gnu2
+pkgver=${_pkgver//-/_}
+pkgrel=2
+
+pkgdesc="GNU IceCat, the standalone web browser based on Mozilla Firefox."
+arch=(i686 x86_64)
+license=(MPL GPL LGPL)
+depends=(alsa-lib dbus-glib ffmpeg gtk2 hunspell icu=57.1 libevent libvpx=1.6.0 libxt mime-types mozilla-common mozilla-searchplugins nss sqlite startup-notification ttf-font)
+makedepends=(diffutils gst-plugins-base-libs imake inetutils libpulse mesa 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'
+ 'gst-plugins-good: h.264 video'
+ 'gst-libav: h.264 video'
+ '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 harfbuzz-1.1.3.patch mozilla-1228540-1.patch
+ vendor.js
+ $pkgname-fixed-loading-icon.png
+ remove-google-play-services-support.patch
+ disable-crypto-hardening-settings.patch
+ disable-spoofSource-referer.patch)
+sha256sums=('0b0a323c7e167c3d23df9c1d33d2ca2d8c5deaca3f43841f4b2a5fac7f5067f9'
+ 'SKIP'
+ 'ced9ddfe6458524cf4f26f86d9bda8f0bcb747c233dc161df6af9ab56dd166ef'
+ 'dd173c9283babb8a04bf55274de05e823161f7d13adb8c5e21dd5a9c0dc549a2'
+ '93e3001ce152e1d142619e215a9ef07dd429943b99d21726c25da9ceb31e31cd'
+ '52df9ffeb52166ed4abd9a132ee4a9017b9c4980f0725ba383610ccfb06d4745'
+ '5bdab2de5520fb4d3dbc453d9f73d20e0e077bf652bc780fc17184ba6c718a47'
+ '4d1e1ddabc9e975ed39f49e134559a29e01cd49439e358233f1ede43bf5a52bf'
+ '329cf6753d29ae64a4336a8a76ee71f0d331a39132159401e4d11de65b708a07'
+ '8a17454d2be90e94694818a1d1a6bdb615eced4d3a7a75af42080c99ce942f2f'
+ 'd1ccbaf0973615c57f7893355e5cd3a89efb4e91071d0ec376e429b50cf6ed19'
+ '977aa49b940f1da049cefa2878a63ac6669a78e63e9d55bb11db7b8f8fb64c33'
+ '68e3a5b47c6d175cc95b98b069a15205f027cab83af9e075818d38610feb6213'
+ '9e651b0f7e7d9d663e8b24077d52bad15f011871747743aff60d6e2d7a45ae5b'
+ '0166aa368420f0bf0aab064b2188e3d852b241efeeb27dee66df2bc15e84b83a'
+ 'c50043266e69f5844e6dce9ea7193af79587dcaa66806932d7867281a176f03e')
+validpgpkeys=(
+ 'A57369A8BABC2542B5A0368C3C76EED7D7E04784' # Ruben Rodriguez
+ 'C92BAA713B8D53D3CAE63FC9E6974752F9704456' # André Silva
+)
+
+prepare() {
+ export GNU_BUILD="gnuzilla-release"
+
+ mv $pkgname-${pkgver%_*} "$srcdir/$GNU_BUILD"
+ cd "$srcdir/$GNU_BUILD"
+
+ # Put gnu_headshadow.png on 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"
+
+ # 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 1.1.3 (following Icedove in [libre])
+ patch -Np0 -i $srcdir/harfbuzz-1.1.3.patch
+ patch -Np1 -i $srcdir/mozilla-1228540-1.patch
+
+ # Patch and remove anything that's left
+ patch -Np1 -i "$srcdir/libre.patch"
+ patch -Np1 -i "$srcdir/remove-google-play-services-support.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
+
+ # 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"
+
+ rm -rf "$pkgdir/usr/lib/$pkgname/browser/"{searchplugins,plugins}
+ ln -sf /usr/lib/mozilla/plugins "$pkgdir/usr/lib/$pkgname/browser/plugins"
+ ln -sf /usr/lib/mozilla/searchplugins "$pkgdir/usr/lib/$pkgname/browser/searchplugins"
+
+ # Workaround for now:
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=658850
+ ln -sf $pkgname "$pkgdir/usr/lib/$pkgname/$pkgname-bin"
+}
diff --git a/unmaintained/icecat/disable-crypto-hardening-settings.patch b/unmaintained/icecat/disable-crypto-hardening-settings.patch
new file mode 100644
index 000000000..3c7dedd77
--- /dev/null
+++ b/unmaintained/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/unmaintained/icecat/disable-spoofSource-referer.patch b/unmaintained/icecat/disable-spoofSource-referer.patch
new file mode 100644
index 000000000..d239b02f1
--- /dev/null
+++ b/unmaintained/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/unmaintained/icecat/firefox-gcc-6.0.patch b/unmaintained/icecat/firefox-gcc-6.0.patch
new file mode 100644
index 000000000..0a74d3616
--- /dev/null
+++ b/unmaintained/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/unmaintained/icecat/gcc6-fix-compilation-for-IceCat.patch b/unmaintained/icecat/gcc6-fix-compilation-for-IceCat.patch
new file mode 100644
index 000000000..2c291567c
--- /dev/null
+++ b/unmaintained/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/unmaintained/icecat/gnu_headshadow.png b/unmaintained/icecat/gnu_headshadow.png
new file mode 100644
index 000000000..e0f73a3bf
--- /dev/null
+++ b/unmaintained/icecat/gnu_headshadow.png
Binary files differ
diff --git a/unmaintained/icecat/harfbuzz-1.1.3.patch b/unmaintained/icecat/harfbuzz-1.1.3.patch
new file mode 100644
index 000000000..98e25914d
--- /dev/null
+++ b/unmaintained/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,