summaryrefslogtreecommitdiff
path: root/libre/icedove
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-05-29 00:17:53 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-05-29 01:16:06 -0300
commit03793386933d6995649d999ce7373eb76fc86a25 (patch)
treefa54d426769dafcf5531489489603dbf58200f6d /libre/icedove
parentb7ea758e3ca7bdfef1f0ddca693061957d5676a5 (diff)
downloadabslibre-03793386933d6995649d999ce7373eb76fc86a25.tar.gz
abslibre-03793386933d6995649d999ce7373eb76fc86a25.tar.bz2
abslibre-03793386933d6995649d999ce7373eb76fc86a25.zip
icedove-1:45.1.0.deb1-1{,.nonprism1}: updating version
Diffstat (limited to 'libre/icedove')
-rw-r--r--libre/icedove/PKGBUILD155
-rw-r--r--libre/icedove/changing-the-default-search-engine.patch21
-rw-r--r--libre/icedove/firefox-gcc-6.0.patch26
-rw-r--r--libre/icedove/fix-missing-files.patch38
-rw-r--r--libre/icedove/mozconfig26
-rw-r--r--libre/icedove/mozilla-1228540-1.patch84
-rw-r--r--libre/icedove/mozilla-1228540.patch9138
-rw-r--r--libre/icedove/vendor.js5
8 files changed, 9399 insertions, 94 deletions
diff --git a/libre/icedove/PKGBUILD b/libre/icedove/PKGBUILD
index ddc12950e..e2ee08730 100644
--- a/libre/icedove/PKGBUILD
+++ b/libre/icedove/PKGBUILD
@@ -1,73 +1,83 @@
-# Maintainer : André Silva <emulatorman@parabola.nu>
-# Contributor : Márcio Silva <coadde@parabola.nu>
+# Maintainer: André Silva <emulatorman@parabola.nu>
+# Contributor: Márcio Silva <coadde@parabola.nu>
# We're getting this from Debian Sid
_debname=icedove
-_debver=38.7.2
+_debver=45.1.0
_debrel=deb1
_debrepo=http://ftp.debian.org/debian/pool/main/
debfile() { echo $@|sed -r 's@(.).*@\1/&/&@'; }
-pkgname=${_debname}
+_pkgname=thunderbird
+pkgname=icedove
epoch=1
-pkgver=${_debver}.${_debrel}
+pkgver=$_debver.$_debrel
pkgrel=1
-pkgdesc="A libre version of Debian Icedove, the standalone mail/news reader based on Mozilla Thunderbird."
-arch=('i686' 'x86_64')
-license=('MPL' 'GPL' 'LGPL')
-url="https://wiki.parabola.nu/${pkgname}"
-depends=('gtk2' 'mozilla-common' 'libxt' 'startup-notification' 'mime-types'
- 'dbus-glib' 'alsa-lib' 'desktop-file-utils' 'hicolor-icon-theme'
- 'libvpx=1.5.0' 'icu=57.1' 'libevent' 'nss' 'hunspell' 'sqlite' 'mozilla-searchplugins')
-makedepends=('unzip' 'zip' 'python2' 'wireless_tools' 'yasm' 'mesa' 'libpulse'
- 'pkg-config' 'autoconf2.13' 'quilt' 'jquery-ui')
+
+pkgdesc="A libre version of Debian Icedove, the standalone mail and news reader based on Mozilla Thunderbird."
+arch=(i686 x86_64)
+license=(MPL GPL LGPL)
+depends=(alsa-lib dbus-glib gtk2 hunspell icu=57.1 libevent libvpx=1.5.0 libxt mime-types mozilla-common nss sqlite startup-notification ttf-font)
+makedepends=(autoconf2.13 diffutils gconf imake inetutils libpulse mesa mozilla-searchplugins pkg-config python2 quilt unzip yasm zip)
+options=(!emptydirs !makeflags)
optdepends=('libcanberra: for sound support')
-replaces=('thunderbird' "${pkgname}-libre")
-conflicts=('thunderbird' "${pkgname}-libre")
-provides=('thunderbird')
-install=${pkgname}.install
-source=("${_debrepo}/`debfile ${_debname}`_${_debver}.orig.tar.xz"
- "${_debrepo}/`debfile ${_debname}`_${_debver}-${_debrel#deb}.debian.tar.xz"
+url="https://wiki.parabola.nu/$pkgname"
+replaces=("$pkgname-libre" "$_pkgname")
+conflicts=("$pkgname-libre" "$_pkgname")
+provides=("$_pkgname")
+install=$pkgname.install
+source=("$_debrepo/`debfile $_debname`_$_debver.orig.tar.xz"
+ "$_debrepo/`debfile $_debname`_$_debver-${_debrel#deb}.debian.tar.xz"
mozconfig
- ${pkgname}.desktop
+ $pkgname.desktop
changing-the-default-search-engine.patch
- vendor.js)
-options=(!emptydirs !makeflags)
-sha256sums=('b423630e772c521aa7f5b390133e6f784270d5b57804675ac498bfd52b8c7f78'
- '76cf43de8f5b8d918efa722da72f648556cd6bcbd7af2a85d4f1fc0df177242a'
- 'e3d0f5f78fede687dfc38a2787c2c8f33c8213be286abeb9176e3dcebabb0b74'
+ firefox-gcc-6.0.patch mozilla-1228540.patch mozilla-1228540-1.patch
+ vendor.js
+ fix-missing-files.patch)
+sha256sums=('2dbb5007b1e0bd23714aec5edfe108a303bc9223576cd0545fcd73dc519978f6'
+ '886e81e42d8d12826be44bb13e39ef86f357c91dcdf90ca32721f1631d45a996'
+ 'cafe29302adcfd6ab4bfb13e6aeef2b405c48877e3c31879945b81e1e3b55cb3'
'0b0d25067c64c6b829c84e5259ffca978e3971f85acc8483f47bdbed5b0b5b6a'
- '9765d9bbcae82d0006766741c813840db46c56ee16f79d39b8d7d96d716ee2d7'
- '798d5bff1e6025e9a803b67f629afac740f16e537b714ee7c7e829b2345fb6a2')
+ 'e1f72c44e31f191271207fc874dcfbf3d504b6b42dc1bb063ba8c7c9ee032130'
+ '4d1e1ddabc9e975ed39f49e134559a29e01cd49439e358233f1ede43bf5a52bf'
+ '2588c567fec88b44b65f0cd111e8769361c138d4c964310684f7bb80066f8f9f'
+ 'd1ccbaf0973615c57f7893355e5cd3a89efb4e91071d0ec376e429b50cf6ed19'
+ '283095a636985e5cbec4056ac23438eafcf9703c3174fcc2bb759bdc40883ab3'
+ '294a2cc7b0477ad285af10ac2a04b767cabec07f03b23da23014bda71caea510')
prepare() {
- export DEBIAN_BUILD=comm-esr${pkgver%%.*}
+ cd "$srcdir/$_pkgname-$_debver"
+ mv "$srcdir/debian" .
export QUILT_PATCHES=debian/patches
export QUILT_REFRESH_ARGS='-p ab --no-timestamps --no-index'
export QUILT_DIFF_ARGS='--no-timestamps'
- mv debian ${srcdir}/${DEBIAN_BUILD}
- cd ${srcdir}/${DEBIAN_BUILD}
-
# Prepare branding for the Icedove packages
- mkdir -v mail/branding/${pkgname}
+ mkdir -v mail/branding/$pkgname
# Copy needed icons
- cp -va debian/${pkgname}-branding/* mail/branding/${pkgname}
+ cp -va debian/$pkgname-branding/* mail/branding/$pkgname
for i in 16 22 24 32 48 256; do
- install -vDm 644 debian/app-icons/${pkgname}${i}.png mail/branding/${pkgname}/mailicon${i}.png
+ install -Dm644 debian/app-icons/$pkgname$i.png \
+ mail/branding/$pkgname/mailicon$i.png
done
for i in 48 64; do
- install -vDm 644 debian/app-icons/${pkgname}${i}.png mail/branding/${pkgname}/content/icon${i}.png
+ install -Dm644 debian/app-icons/$pkgname$i.png \
+ mail/branding/$pkgname/content/icon$i.png
done
- cp -va debian/preview.png mail/themes/linux/mail/preview.png
+ cp -av debian/preview.png mail/themes/linux/mail/preview.png
# Useless since we are doing it ourselves
+ rm -rv debian/patches/icedove-l10n || true
+ rm -rv debian/patches/iceowl-l10n || true
rm -v debian/patches/debian-hacks/changing-the-default-search-engine.patch || true
quilt push -av
+ # Fix missing files
+ patch -Np1 -i "$srcdir/fix-missing-files.patch"
+
# Remove url-classifier from package-manifest.in to build and disable Phishing Protection
sed -i '\|Phishing Protection|d
\|UrlClassifier|d
@@ -76,7 +86,8 @@ prepare() {
' mail/installer/package-manifest.in
# Fix branding
- sed -i 's|Icedove Mail/News|Icedove|' mail/branding/icedove/locales/en-US/brand.{dtd,properties}
+ sed -i 's|Icedove Mail/News|Icedove|
+ ' mail/branding/icedove/locales/en-US/brand.{dtd,properties}
# Replace common URLs
sed -i '\|extensions[.]getAddons[.]get[.]url| s|https://services[.]addons[.]mozilla[.]org.\+["][)][;]|https://directory.fsf.org/wiki/Icedove");|g;
@@ -85,63 +96,69 @@ prepare() {
\|extensions[.]webservice[.]discoverURL| s|https://services[.]addons[.]mozilla[.]org.\+["][)][;]|https://directory.fsf.org/wiki/Icedove");|g;
' mail/app/profile/all-thunderbird.js
- cp -v ${srcdir}/mozconfig .mozconfig
+ # Required for GCC 6
+ patch -d mozilla -Np1 < ../firefox-gcc-6.0.patch
+ patch -d mozilla -Np1 < ../mozilla-1228540.patch
+ patch -d mozilla -Np1 < ../mozilla-1228540-1.patch
+
+ cp -v "$srcdir/mozconfig" .mozconfig
- # Configure script misdetects the preprocessor without an optimization level
- # https://bugs.archlinux.org/task/34644
- sed -i '/ac_cpp=/s/$CPPFLAGS/& -O2/' mozilla/configure
+ mkdir "$srcdir/path"
+ ln -s /usr/bin/python2 "$srcdir/path/python"
# Change the default search engine using our system-provided searchplugins
- patch -Np1 -i ${srcdir}/changing-the-default-search-engine.patch
+ patch -Np1 -i "$srcdir/changing-the-default-search-engine.patch"
- # Add symlinks to use jquery files built by us
- ln -vs /usr/share/javascript/jquery/jquery.min.js mail/jquery
- ln -vs /usr/share/javascript/jquery-ui/jquery-ui.min.js mail/jquery
+ # Load our searchplugins
+ rm -rv mail/locales/en-US/searchplugins
+ cp -av /usr/lib/mozilla/searchplugins mail/locales/en-US
}
build() {
- export DEBIAN_BUILD=comm-esr${pkgver%%.*}
+ cd "$srcdir/$_pkgname-$_debver"
- cd ${srcdir}/${DEBIAN_BUILD}
+ # _FORTIFY_SOURCE causes configure failures
+ CPPFLAGS+=" -O2"
- export PYTHON=/usr/bin/python2
+ # GCC 6
+ CFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse"
+ CXXFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse"
+
+ export PATH="$srcdir/path:$PATH"
make -f client.mk build
}
package() {
- export DEBIAN_BUILD=comm-esr${pkgver%%.*}
-
- cd ${srcdir}/${DEBIAN_BUILD}
-
- make -f client.mk DESTDIR=${pkgdir} install
+ cd "$srcdir/$_pkgname-$_debver"
+ make -f client.mk DESTDIR="$pkgdir" INSTALL_SDK= install
- install -vDm 644 ${srcdir}/vendor.js ${pkgdir}/usr/lib/${pkgname}/defaults/preferences/vendor.js
+ install -Dm644 ../vendor.js "$pkgdir/usr/lib/$pkgname/defaults/preferences/vendor.js"
# Install Icedove menu icon
- install -vDm 644 debian/${pkgname}.xpm ${pkgdir}/usr/share/pixmaps/${pkgname}.xpm
+ install -Dm644 debian/$pkgname.xpm "$pkgdir/usr/share/pixmaps/$pkgname.xpm"
# Install Icedove icons
+ brandingdir=debian/app-icons
+ icondir="$pkgdir/usr/share/icons/hicolor"
for i in 16 22 24 32 48 64 128 256; do
- install -vDm 644 debian/app-icons/${pkgname}${i}.png ${pkgdir}/usr/share/icons/hicolor/${i}x${i}/apps/${pkgname}.png
+ install -Dm644 "$brandingdir/$pkgname$i.png" \
+ "$icondir/${i}x${i}/apps/$pkgname.png"
done
- install -vDm 644 debian/app-icons/${pkgname}big.svg ${pkgdir}/usr/share/icons/hicolor/scalable/apps/${pkgname}.svg
+ install -Dm644 "$brandingdir/${pkgname}big.svg" \
+ "$icondir/scalable/apps/$pkgname.svg"
# Install Icedove desktop
- install -vDm 644 ${srcdir}/${pkgname}.desktop ${pkgdir}/usr/share/applications/${pkgname}.desktop
+ install -d "$pkgdir/usr/share/applications"
+ install -m644 "$srcdir/$pkgname.desktop" \
+ "$pkgdir/usr/share/applications"
# Use system-provided dictionaries
- rm -vrf ${pkgdir}/usr/lib/${pkgname}/{dictionaries,hyphenation,searchplugins}
- ln -vsf /usr/share/hunspell ${pkgdir}/usr/lib/${pkgname}/dictionaries
- ln -vsf /usr/share/hyphen ${pkgdir}/usr/lib/${pkgname}/hyphenation
-
- # Use system-provided searchplugins
- ln -vsf /usr/lib/mozilla/searchplugins ${pkgdir}/usr/lib/${pkgname}/searchplugins
+ rm -rf "$pkgdir/usr/lib/$pkgname/"{dictionaries,hyphenation}
+ ln -s /usr/share/hunspell "$pkgdir/usr/lib/$pkgname/dictionaries"
+ ln -s /usr/share/hyphen "$pkgdir/usr/lib/$pkgname/hyphenation"
# Replace duplicate binary with symlink
# https://bugzilla.mozilla.org/show_bug.cgi?id=658850
- ln -vsf ${pkgname} ${pkgdir}/usr/lib/${pkgname}/${pkgname}-bin
-
- # Remove development stuff
- rm -vr ${pkgdir}/usr/{include,lib/${pkgname}-devel,share/idl}
+ ln -sf $pkgname "$pkgdir/usr/lib/$pkgname/$pkgname-bin"
}
diff --git a/libre/icedove/changing-the-default-search-engine.patch b/libre/icedove/changing-the-default-search-engine.patch
index 845e4f2fa..37df3e851 100644
--- a/libre/icedove/changing-the-default-search-engine.patch
+++ b/libre/icedove/changing-the-default-search-engine.patch
@@ -1,6 +1,7 @@
-diff -Nur comm-esr38.orig/mail/locales/en-US/chrome/messenger-region/region.properties comm-esr38/mail/locales/en-US/chrome/messenger-region/region.properties
---- comm-esr38.orig/mail/locales/en-US/chrome/messenger-region/region.properties 2015-07-07 14:34:06.000000000 -0300
-+++ comm-esr38/mail/locales/en-US/chrome/messenger-region/region.properties 2015-08-16 13:30:55.466053010 -0300
+diff --git a/mail/locales/en-US/chrome/messenger-region/region.properties b/mail/locales/en-US/chrome/messenger-region/region.properties
+index fcc870d..f810450 100644
+--- a/mail/locales/en-US/chrome/messenger-region/region.properties
++++ b/mail/locales/en-US/chrome/messenger-region/region.properties
@@ -3,12 +3,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -18,13 +19,21 @@ diff -Nur comm-esr38.orig/mail/locales/en-US/chrome/messenger-region/region.prop
# To make mapit buttons to disappear in the addressbook, specify empty string. For example:
# mail.addr_book.mapit_url.format=
-@@ -19,8 +19,8 @@
- # @ST == state
+@@ -23,14 +23,12 @@ browser.search.order.3=
# @ZI == zip code
# @CO == country
+ # Default map service:
-mail.addr_book.mapit_url.format=http://maps.google.com/maps?q=@A1%20@A2%20@CI%20@ST%20@ZI%20@CO
++mail.addr_book.mapit_url.format=http://nominatim.openstreetmap.org/search.php?polygon=1&q=@A1%2C@A2%2C@CI%2C@ST%2C@ZI%2C@CO
+ # List of available map services (up to 5 can be defined here):
+-mail.addr_book.mapit_url.1.name=Google Maps
+-mail.addr_book.mapit_url.1.format=http://maps.google.com/maps?q=@A1%20@A2%20@CI%20@ST%20@ZI%20@CO
+-mail.addr_book.mapit_url.2.name=OpenStreetMap
+-mail.addr_book.mapit_url.2.format=http://nominatim.openstreetmap.org/search.php?polygon=1&q=@A1%2C@A2%2C@CI%2C@ST%2C@ZI%2C@CO
++mail.addr_book.mapit_url.1.name=OpenStreetMap
++mail.addr_book.mapit_url.1.format=http://nominatim.openstreetmap.org/search.php?polygon=1&q=@A1%2C@A2%2C@CI%2C@ST%2C@ZI%2C@CO
+
-mailnews.messageid_browser.url=http://groups.google.com/search?as_umsgid=%mid
-+mail.addr_book.mapit_url.format=
+mailnews.messageid_browser.url=
# Recognize non-standard versions of "Re:" in subjects from localized versions of MS Outlook et al.
diff --git a/libre/icedove/firefox-gcc-6.0.patch b/libre/icedove/firefox-gcc-6.0.patch
new file mode 100644
index 000000000..0a74d3616
--- /dev/null
+++ b/libre/icedove/firefox-gcc-6.0.patch
@@ -0,0 +1,26 @@
+diff -up firefox-44.0/nsprpub/config/make-system-wrappers.pl.back firefox-44.0/nsprpub/config/make-system-wrappers.pl
+--- firefox-44.0/nsprpub/config/make-system-wrappers.pl.back 2016-01-24 00:23:49.000000000 +0100
++++ firefox-44.0/nsprpub/config/make-system-wrappers.pl 2016-02-02 14:58:45.064112655 +0100
+@@ -19,7 +19,9 @@ while (<STDIN>) {
+ open OUT, ">$output_dir/$_";
+ print OUT "#pragma GCC system_header\n"; # suppress include_next warning
+ print OUT "#pragma GCC visibility push(default)\n";
++ print OUT "#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS\n";
+ print OUT "#include_next \<$_\>\n";
++ print OUT "#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS\n";
+ print OUT "#pragma GCC visibility pop\n";
+ close OUT;
+ }
+diff -up firefox-44.0/mozglue/build/arm.cpp.old firefox-44.0/mozglue/build/arm.cpp
+--- firefox-44.0/mozglue/build/arm.cpp.old 2016-02-03 10:07:29.879526500 +0100
++++ firefox-44.0/mozglue/build/arm.cpp 2016-02-03 10:08:11.062697517 +0100
+@@ -104,7 +104,9 @@ check_neon(void)
+
+ # elif defined(__linux__) || defined(ANDROID)
+ # include <stdio.h>
++#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+ # include <stdlib.h>
++#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
+ # include <string.h>
+
+ enum{
diff --git a/libre/icedove/fix-missing-files.patch b/libre/icedove/fix-missing-files.patch
new file mode 100644
index 000000000..04cf3d35e
--- /dev/null
+++ b/libre/icedove/fix-missing-files.patch
@@ -0,0 +1,38 @@
+diff --git a/mailnews/base/test/unit/xpcshell.ini b/mailnews/base/test/unit/xpcshell.ini
+index 9644fdf..f098fad 100644
+--- a/mailnews/base/test/unit/xpcshell.ini
++++ b/mailnews/base/test/unit/xpcshell.ini
+@@ -19,7 +19,6 @@ support-files = nodelist_test.xml data/*
+ [test_bug471682.js]
+ [test_bug514945.js]
+ [test_compactFailure.js]
+-[test_compactColumnSave.js]
+ [test_copyChaining.js]
+ [test_copyThenMoveManual.js]
+ [test_copyToInvalidDB.js]
+diff --git a/mozilla/intl/uconv/tests/moz.build b/mozilla/intl/uconv/tests/moz.build
+index 4223d2e..fae03f4 100644
+--- a/mozilla/intl/uconv/tests/moz.build
++++ b/mozilla/intl/uconv/tests/moz.build
+@@ -4,8 +4,6 @@
+ # 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/.
+
+-XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
+-
+ # Tests disabled because they dont work in libxul builds.
+ #MOZILLA_INTERNAL_API = True
+ #
+diff --git a/mozilla/parser/xml/moz.build b/mozilla/parser/xml/moz.build
+index 484f6d1..d072795 100644
+--- a/mozilla/parser/xml/moz.build
++++ b/mozilla/parser/xml/moz.build
+@@ -4,8 +4,6 @@
+ # 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/.
+
+-TEST_DIRS += ['test']
+-
+ XPIDL_SOURCES += [
+ 'nsIMozSAXXMLDeclarationHandler.idl',
+ 'nsISAXAttributes.idl',
diff --git a/libre/icedove/mozconfig b/libre/icedove/mozconfig
index 20cb08590..e09f2c16b 100644
--- a/libre/icedove/mozconfig
+++ b/libre/icedove/mozconfig
@@ -1,50 +1,40 @@
-mk_add_options MOZ_CO_PROJECT=mail
ac_add_options --enable-application=mail
ac_add_options --prefix=/usr
ac_add_options --libdir=/usr/lib
+ac_add_options --enable-release
+ac_add_options --enable-gold
ac_add_options --enable-pie
# Icedove
ac_add_options --with-branding=mail/branding/icedove
-#ac_add_options --enable-calendar
# System libraries
ac_add_options --with-system-nspr
ac_add_options --with-system-nss
+ac_add_options --with-system-icu
ac_add_options --with-system-jpeg
ac_add_options --with-system-zlib
ac_add_options --with-system-bz2
-ac_add_options --with-system-png
ac_add_options --with-system-libevent
ac_add_options --with-system-libvpx
-ac_add_options --with-system-icu
ac_add_options --enable-system-hunspell
ac_add_options --enable-system-sqlite
ac_add_options --enable-system-ffi
-ac_add_options --enable-system-cairo
ac_add_options --enable-system-pixman
# Features
+ac_add_options --enable-calendar
ac_add_options --enable-startup-notification
-ac_add_options --enable-gio
-
ac_add_options --disable-gstreamer
-ac_add_options --disable-gnomevfs
-ac_add_options --disable-crashreporter
ac_add_options --disable-updater
-ac_add_options --disable-tests
-ac_add_options --disable-mochitest
-ac_add_options --disable-installer
-ac_add_options --disable-debug-symbols
-
-# Optimization
-ac_add_options --enable-optimize
+ac_add_options --disable-crashreporter
-export MOZILLA_OFFICIAL=1
-mk_add_options MOZILLA_OFFICIAL=1
+STRIP_FLAGS="--strip-debug"
# Parabola features
ac_add_options --disable-official-branding
ac_add_options --disable-safe-browsing
ac_add_options --disable-url-classifier
+
+# vim:set ft=sh:
diff --git a/libre/icedove/mozilla-1228540-1.patch b/libre/icedove/mozilla-1228540-1.patch
new file mode 100644
index 000000000..be6ffc316
--- /dev/null
+++ b/libre/icedove/mozilla-1228540-1.patch
@@ -0,0 +1,84 @@
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1452675061 0
+# Wed Jan 13 08:51:01 2016 +0000
+# Node ID cf699e95e98829b465b64a7e0281d95ec851ce8c
+# Parent 3c9f357598e86c2f593e9895d5725bf3498f8f5a
+Bug 1228540 - pt 2 - Remove our HBGetGlyphHOrigin callback, as the default behavior is sufficient.
+
+diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp
+--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
++++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
+@@ -349,27 +349,16 @@ gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb
+ static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
+ // Currently, we don't offer gfxFont subclasses a method to override this
+ // and provide hinted platform-specific vertical advances (analogous to the
+ // GetGlyphWidth method for horizontal advances). If that proves necessary,
+ // we'll add a new gfxFont method and call it from here.
+ return fcd->mShaper->GetGlyphVAdvance(glyph);
+ }
+
+-/* static */
+-hb_bool_t
+-gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
+- hb_codepoint_t glyph,
+- hb_position_t *x, hb_position_t *y,
+- void *user_data)
+-{
+- // We work in horizontal coordinates, so no origin adjustment needed here.
+- return true;
+-}
+-
+ struct VORG {
+ AutoSwap_PRUint16 majorVersion;
+ AutoSwap_PRUint16 minorVersion;
+ AutoSwap_PRInt16 defaultVertOriginY;
+ AutoSwap_PRUint16 numVertOriginYMetrics;
+ };
+
+ struct VORGrec {
+@@ -1262,19 +1251,16 @@ gfxHarfBuzzShaper::Initialize()
+ hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
+ HBGetGlyphHAdvance,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs,
+ HBGetGlyphVAdvance,
+ nullptr, nullptr);
+- hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs,
+- HBGetGlyphHOrigin,
+- nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
+ HBGetGlyphVOrigin,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(sHBFontFuncs,
+ HBGetGlyphExtents,
+ nullptr, nullptr);
+ hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs,
+ HBGetContourPoint,
+diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h
+--- a/gfx/thebes/gfxHarfBuzzShaper.h
++++ b/gfx/thebes/gfxHarfBuzzShaper.h
+@@ -56,21 +56,16 @@ public:
+ hb_codepoint_t glyph, void *user_data);
+
+ // get harfbuzz vertical advance in 16.16 fixed point format.
+ static hb_position_t
+ HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph, void *user_data);
+
+ static hb_bool_t
+- HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
+- hb_codepoint_t glyph,
+- hb_position_t *x, hb_position_t *y,
+- void *user_data);
+- static hb_bool_t
+ HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data);
+
+ hb_position_t GetHKerning(uint16_t aFirstGlyph,
+ uint16_t aSecondGlyph) const;
+
diff --git a/libre/icedove/mozilla-1228540.patch b/libre/icedove/mozilla-1228540.patch
new file mode 100644
index 000000000..3fac3de05
--- /dev/null
+++ b/libre/icedove/mozilla-1228540.patch
@@ -0,0 +1,9138 @@
+# HG changeset patch
+# User Jonathan Kew <jkew@mozilla.com>
+# Date 1452639380 0
+# Tue Jan 12 22:56:20 2016 +0000
+# Node ID 3c9f357598e86c2f593e9895d5725bf3498f8f5a
+# Parent e790bba372f14241addda469a4bdb7ab00786ab3
+Bug 1228540 - Update harfbuzz to release 1.1.3.
+
+diff --git a/gfx/harfbuzz/src/Makefile.am b/gfx/harfbuzz/src/Makefile.am
+--- a/gfx/harfbuzz/src/Makefile.am
++++ b/gfx/harfbuzz/src/Makefile.am
+@@ -43,16 +43,17 @@ HBSOURCES = \
+ hb-open-type-private.hh \
+ hb-ot-cmap-table.hh \
+ hb-ot-glyf-table.hh \
+ hb-ot-head-table.hh \
+ hb-ot-hhea-table.hh \
+ hb-ot-hmtx-table.hh \
+ hb-ot-maxp-table.hh \
+ hb-ot-name-table.hh \
++ hb-ot-os2-table.hh \
+ hb-ot-tag.cc \
+ hb-private.hh \
+ hb-set-private.hh \
+ hb-set.cc \
+ hb-shape.cc \
+ hb-shape-plan-private.hh \
+ hb-shape-plan.cc \
+ hb-shaper-list.hh \
+@@ -387,17 +388,24 @@ dist_check_SCRIPTS = \
+ check-defs.sh \
+ check-header-guards.sh \
+ check-includes.sh \
+ check-libstdc++.sh \
+ check-static-inits.sh \
+ check-symbols.sh \
+ $(NULL)
+
+-TESTS = $(dist_check_SCRIPTS)
++check_PROGRAMS = \
++ test-ot-tag \
++ $(NULL)
++test_ot_tag_SOURCES = hb-ot-tag.cc
++test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
++test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
++
++TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
+ TESTS_ENVIRONMENT = \
+ srcdir="$(srcdir)" \
+ MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
+ HBSOURCES="$(HBSOURCES)" \
+ HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
+ $(NULL)
+
+ if HAVE_INTROSPECTION
+@@ -414,16 +422,17 @@ HarfBuzz_0_0_gir_CFLAGS = \
+ $(INCLUDES) \
+ $(HBCFLAGS) \
+ -DHB_H \
+ -DHB_H_IN \
+ -DHB_OT_H \
+ -DHB_OT_H_IN \
+ -DHB_GOBJECT_H \
+ -DHB_GOBJECT_H_IN \
++ -DHB_EXTERN= \
+ $(NULL)
+ HarfBuzz_0_0_gir_LIBS = \
+ libharfbuzz.la \
+ libharfbuzz-gobject.la \
+ $(NULL)
+ HarfBuzz_0_0_gir_FILES = \
+ $(HBHEADERS) \
+ $(HBNODISTHEADERS) \
+diff --git a/gfx/harfbuzz/src/check-header-guards.sh b/gfx/harfbuzz/src/check-header-guards.sh
+--- a/gfx/harfbuzz/src/check-header-guards.sh
++++ b/gfx/harfbuzz/src/check-header-guards.sh
+@@ -4,22 +4,21 @@ LC_ALL=C
+ export LC_ALL
+
+ test -z "$srcdir" && srcdir=.
+ stat=0
+
+ 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
+ fi
+ done
+
+ exit $stat
+diff --git a/gfx/harfbuzz/src/gen-indic-table.py b/gfx/harfbuzz/src/gen-indic-table.py
+--- a/gfx/harfbuzz/src/gen-indic-table.py
++++ b/gfx/harfbuzz/src/gen-indic-table.py
+@@ -86,16 +86,17 @@ short = [{
+ "Bindu": 'Bi',
+ "Cantillation_Mark": 'Ca',
+ "Joiner": 'ZWJ',
+ "Non_Joiner": 'ZWNJ',
+ "Number": 'Nd',
+ "Visarga": 'Vs',
+ "Vowel": 'Vo',
+ "Vowel_Dependent": 'M',
++ "Consonant_Prefixed": 'CPrf',
+ "Other": 'x',
+ },{
+ "Not_Applicable": 'x',
+ }]
+ all_shorts = [{},{}]
+
+ # Add some of the values, to make them more readable, and to avoid duplicates
+
+diff --git a/gfx/harfbuzz/src/hb-atomic-private.hh b/gfx/harfbuzz/src/hb-atomic-private.hh
+--- a/gfx/harfbuzz/src/hb-atomic-private.hh
++++ b/gfx/harfbuzz/src/hb-atomic-private.hh
+@@ -114,16 +114,41 @@ typedef int hb_atomic_int_impl_t;
+ 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;
++}
++
++typedef int hb_atomic_int_impl_t;
++#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
++#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V))
++
++#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
++#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
++
+ #elif !defined(HB_NO_MT)
+
+ #define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
+
+ typedef volatile int hb_atomic_int_impl_t;
+ #define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+ #define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
+
+diff --git a/gfx/harfbuzz/src/hb-blob.h b/gfx/harfbuzz/src/hb-blob.h
+--- a/gfx/harfbuzz/src/hb-blob.h
++++ b/gfx/harfbuzz/src/hb-blob.h
+@@ -59,68 +59,68 @@ typedef enum {
+ HB_MEMORY_MODE_DUPLICATE,
+ HB_MEMORY_MODE_READONLY,
+ HB_MEMORY_MODE_WRITABLE,
+ HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
+ } hb_memory_mode_t;
+
+ 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,
+ void *user_data,
+ hb_destroy_func_t destroy);
+
+ /* Always creates with MEMORY_MODE_READONLY.
+ * Even if the parent blob is writable, we don't
+ * want the user of the sub-blob to be able to
+ * 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,
+ hb_destroy_func_t destroy,
+ 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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_BLOB_H */
+diff --git a/gfx/harfbuzz/src/hb-buffer-private.hh b/gfx/harfbuzz/src/hb-buffer-private.hh
+--- a/gfx/harfbuzz/src/hb-buffer-private.hh
++++ b/gfx/harfbuzz/src/hb-buffer-private.hh
+@@ -119,16 +119,21 @@ struct hb_buffer_t {
+
+ /* Text before / after the main buffer contents.
+ * Always in Unicode, and ordered outward.
+ * Index 0 is for "pre-context", 1 for "post-context". */
+ static const unsigned int CONTEXT_LENGTH = 5;
+ 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 */
+
+ HB_INTERNAL void reset (void);
+ HB_INTERNAL void clear (void);
+
+ inline unsigned int backtrack_len (void) const
+ { return have_output? out_len : idx; }
+@@ -169,23 +174,22 @@ struct hb_buffer_t {
+ /* Copies glyph at idx to output and advance idx.
+ * If there's no output, just advance idx. */
+ inline void
+ next_glyph (void)
+ {
+ if (have_output)
+ {
+ if (unlikely (out_info != info || out_len != idx)) {
+- if (unlikely (!make_room_for (1, 1)))
+- goto done;
++ if (unlikely (!make_room_for (1, 1))) return;
+ out_info[out_len] = info[idx];
+ }
+ out_len++;
+ }
+- done:
++
+ idx++;
+ }
+
+ /* Advance idx without copying to output. */
+ inline void skip_glyph (void) { idx++; }
+
+ inline void reset_masks (hb_mask_t mask)
+ {
+@@ -229,16 +233,29 @@ struct hb_buffer_t {
+ HB_INTERNAL bool shift_forward (unsigned int count);
+
+ typedef long scratch_buffer_t;
+ 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);
+ };
+
+
+ #define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
+ b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
+ sizeof (b->info[0].var), owner)
+ #define HB_BUFFER_ALLOCATE_VAR(b, var) \
+ HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
+diff --git a/gfx/harfbuzz/src/hb-buffer-serialize.cc b/gfx/harfbuzz/src/hb-buffer-serialize.cc
+--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc
++++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc
+@@ -31,55 +31,61 @@ static const char *serialize_formats[] =
+ "text",
+ "json",
+ NULL
+ };
+
+ /**
+ * 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: 0.9.2
++ * Since: 0.9.7
+ **/
+ const char **
+ hb_buffer_serialize_list_formats (void)
+ {
+ return serialize_formats;
+ }
+
+ /**
+ * 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: 0.9.2
++ * Since: 0.9.7
+ **/
+ hb_buffer_serialize_format_t
+ hb_buffer_serialize_format_from_string (const char *str, int len)
+ {
+ /* Upper-case it. */
+ return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
+ }
+
+ /**
+ * 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: 0.9.2
++ * Since: 0.9.7
+ **/
+ const char *
+ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+ {
+ switch (format)
+ {
+ case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
+ case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
+@@ -237,56 +243,86 @@ static unsigned int
+ *buf = '\0';
+ } else
+ return i - start;
+ }
+
+ 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: 0.9.2
++ * Since: 0.9.7
+ **/
+ 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)
+ {
+ assert (start <= end && end <= buffer->len);
+
+ unsigned int sconsumed;
+ if (!buf_consumed)
+ buf_consumed = &sconsumed;
+ *buf_consumed = 0;
+
+ 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;
+
+ if (!font)
+ font = hb_font_get_empty ();
+
+ switch (format)
+ {
+@@ -350,28 +386,28 @@ parse_int (const char *pp, const char *e
+ return true;
+ }
+
+ #include "hb-buffer-deserialize-json.hh"
+ #include "hb-buffer-deserialize-text.hh"
+
+ /**
+ * hb_buffer_deserialize_glyphs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len:
+ * @end_ptr: (out):
+ * @font:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+- * Since: 0.9.2
++ * Since: 0.9.7
+ **/
+ 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 */
+ hb_buffer_serialize_format_t format)
+diff --git a/gfx/harfbuzz/src/hb-buffer.cc b/gfx/harfbuzz/src/hb-buffer.cc
+--- a/gfx/harfbuzz/src/hb-buffer.cc
++++ b/gfx/harfbuzz/src/hb-buffer.cc
+@@ -30,33 +30,59 @@
+ #include "hb-buffer-private.hh"
+ #include "hb-utf-private.hh"
+
+
+ #ifndef HB_DEBUG_BUFFER
+ #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)
+ {
+ return a->direction == b->direction &&
+ a->script == b->script &&
+ a->language == b->language &&
+ a->reserved1 == b->reserved1 &&
+ a->reserved2 == b->reserved2;
+
+ }
+
+ /**
++ * 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)
+ {
+ return (unsigned int) p->direction ^
+ (unsigned int) p->script ^
+ (intptr_t) (p->language);
+@@ -319,75 +345,62 @@ hb_buffer_t::swap_buffers (void)
+ }
+
+
+ void
+ hb_buffer_t::replace_glyphs (unsigned int num_in,
+ unsigned int num_out,
+ const uint32_t *glyph_data)
+ {
+- if (unlikely (!make_room_for (num_in, num_out)))
+- goto done;
+- {
++ if (unlikely (!make_room_for (num_in, num_out))) return;
+
+ merge_clusters (idx, idx + num_in);
+
+ hb_glyph_info_t orig_info = info[idx];
+ hb_glyph_info_t *pinfo = &out_info[out_len];
+ for (unsigned int i = 0; i < num_out; i++)
+ {
+ *pinfo = orig_info;
+ pinfo->codepoint = glyph_data[i];
+ pinfo++;
+ }
+
++ idx += num_in;
+ out_len += num_out;
+- }
+-done:
+- idx += num_in;
+ }
+
+ void
+ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
+ {
+- if (unlikely (!make_room_for (0, 1)))
+- goto done;
++ if (unlikely (!make_room_for (0, 1))) return;
+
+ out_info[out_len] = info[idx];
+ out_info[out_len].codepoint = glyph_index;
+
+ out_len++;
+-done:
+- ;
+ }
+
+ void
+ hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
+ {
+- if (unlikely (!make_room_for (0, 1)))
+- goto done;
++ if (unlikely (!make_room_for (0, 1))) return;
+
+ out_info[out_len] = glyph_info;
+
+ out_len++;
+-done:
+- ;
+ }
+
+ void
+ hb_buffer_t::copy_glyph (void)
+ {
+- if (unlikely (!make_room_for (0, 1)))
+- goto done;
++ if (unlikely (!make_room_for (0, 1))) return;
+
+ out_info[out_len] = info[idx];
+
+ out_len++;
+-done:
+- ;
+ }
+
+ bool
+ hb_buffer_t::move_to (unsigned int i)
+ {
+ if (!have_output)
+ {
+ assert (i <= len);
+@@ -395,17 +408,17 @@ hb_buffer_t::move_to (unsigned int i)
+ return true;
+ }
+
+ assert (i <= out_len + (len - idx));
+
+ if (out_len < i)
+ {
+ unsigned int count = i - out_len;
+- if (unlikely (!make_room_for (count, count))) return false; // XXX verify bailout
++ if (unlikely (!make_room_for (count, count))) return false;
+
+ memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
+ idx += count;
+ out_len += count;
+ }
+ else if (out_len > i)
+ {
+ /* Tricky part: rewinding... */
+@@ -422,25 +435,23 @@ hb_buffer_t::move_to (unsigned int i)
+
+ return true;
+ }
+
+ void
+ hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+ {
+ if (unlikely (out_info != info || out_len != idx)) {
+- if (unlikely (!make_room_for (1, 1)))
+- goto out;
++ if (unlikely (!make_room_for (1, 1))) return;
+ out_info[out_len] = info[idx];
+ }
+ out_info[out_len].codepoint = glyph_index;
+
++ idx++;
+ out_len++;
+-out:
+- idx++;
+ }
+
+
+ void
+ hb_buffer_t::set_masks (hb_mask_t value,
+ hb_mask_t mask,
+ unsigned int cluster_start,
+ unsigned int cluster_end)
+@@ -716,19 +727,24 @@ void hb_buffer_t::deallocate_var_all (vo
+ memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
+ }
+
+ /* Public API */
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_buffer_t *
+ hb_buffer_create (void)
+ {
+ hb_buffer_t *buffer;
+
+@@ -773,54 +789,60 @@ hb_buffer_get_empty (void)
+ /* Zero is good enough for everything else. */
+ };
+
+ return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_buffer_t *
+ hb_buffer_reference (hb_buffer_t *buffer)
+ {
+ return hb_object_reference (buffer);
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ void
+ hb_buffer_destroy (hb_buffer_t *buffer)
+ {
+ if (!hb_object_destroy (buffer)) return;
+
+ hb_unicode_funcs_destroy (buffer->unicode);
+
+ 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:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+@@ -834,17 +856,17 @@ hb_buffer_set_user_data (hb_buffer_t
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+ {
+ return hb_object_set_user_data (buffer, key, data, destroy, replace);
+ }
+
+ /**
+ * hb_buffer_get_user_data: (skip)
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @key:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+@@ -853,50 +875,52 @@ hb_buffer_get_user_data (hb_buffer_t
+ hb_user_data_key_t *key)
+ {
+ return hb_object_get_user_data (buffer, key);
+ }
+
+
+ /**
+ * 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: 0.9.5
+ **/
+ void
+ hb_buffer_set_content_type (hb_buffer_t *buffer,
+ hb_buffer_content_type_t content_type)
+ {
+ buffer->content_type = content_type;
+ }
+
+ /**
+ * 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: 0.9.5
+ **/
+ hb_buffer_content_type_t
+ hb_buffer_get_content_type (hb_buffer_t *buffer)
+ {
+ return buffer->content_type;
+ }
+
+
+ /**
+ * hb_buffer_set_unicode_funcs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @unicode_funcs:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
+@@ -911,210 +935,238 @@ hb_buffer_set_unicode_funcs (hb_buffer_t
+
+ hb_unicode_funcs_reference (unicode_funcs);
+ hb_unicode_funcs_destroy (buffer->unicode);
+ buffer->unicode = unicode_funcs;
+ }
+
+ /**
+ * hb_buffer_get_unicode_funcs:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 0.9.2
+ **/
+ hb_unicode_funcs_t *
+ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
+ {
+ return buffer->unicode;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ void
+ hb_buffer_set_direction (hb_buffer_t *buffer,
+ hb_direction_t direction)
+
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->props.direction = direction;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_direction_t
+ hb_buffer_get_direction (hb_buffer_t *buffer)
+ {
+ return buffer->props.direction;
+ }
+
+ /**
+ * 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.
++ *
++ * 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,
+ hb_script_t script)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->props.script = script;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_script_t
+ hb_buffer_get_script (hb_buffer_t *buffer)
+ {
+ return buffer->props.script;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ void
+ hb_buffer_set_language (hb_buffer_t *buffer,
+ hb_language_t language)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->props.language = language;
+ }
+
+ /**
+ * hb_buffer_get_language:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_language().
+ *
+ * Return value: (transfer none):
++ * The #hb_language_t of the buffer. Must not be freed by the caller.
+ *
+ * Since: 0.9.2
+ **/
+ hb_language_t
+ hb_buffer_get_language (hb_buffer_t *buffer)
+ {
+ return buffer->props.language;
+ }
+
+ /**
+ * 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: 0.9.7
+ **/
+ void
+ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+ const hb_segment_properties_t *props)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->props = *props;
+ }
+
+ /**
+ * hb_buffer_get_segment_properties:
+- * @buffer: a buffer.
+- * @props: (out):
++ * @buffer: an #hb_buffer_t.
++ * @props: (out): the output #hb_segment_properties_t.
+ *
+- *
++ * Sets @props to the #hb_segment_properties_t of @buffer.
+ *
+ * Since: 0.9.7
+ **/
+ void
+ hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+ hb_segment_properties_t *props)
+ {
+ *props = buffer->props;
+ }
+
+
+ /**
+ * 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: 0.9.7
+ **/
+ void
+ hb_buffer_set_flags (hb_buffer_t *buffer,
+ hb_buffer_flags_t flags)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->flags = flags;
+ }
+
+ /**
+ * hb_buffer_get_flags:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+- *
++ * See hb_buffer_set_flags().
+ *
+ * Return value:
++ * The @buffer flags.
+ *
+ * Since: 0.9.7
+ **/
+ hb_buffer_flags_t
+ hb_buffer_get_flags (hb_buffer_t *buffer)
+ {
+ return buffer->flags;
+ }
+
+ /**
+ * hb_buffer_set_cluster_level:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ * @cluster_level:
+ *
+ *
+ *
+ * Since: 0.9.42
+ **/
+ void
+ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
+@@ -1123,155 +1175,172 @@ hb_buffer_set_cluster_level (hb_buffer_t
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->cluster_level = cluster_level;
+ }
+
+ /**
+ * hb_buffer_get_cluster_level:
+- * @buffer: a buffer.
++ * @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.
++ *
++ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
+ *
+ * Since: 0.9.31
+ **/
+ void
+ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
+ hb_codepoint_t replacement)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->replacement = replacement;
+ }
+
+ /**
+ * 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: 0.9.31
+ **/
+ hb_codepoint_t
+ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
+ {
+ return buffer->replacement;
+ }
+
+
+ /**
+ * 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: 0.9.2
+ **/
+ void
+ hb_buffer_reset (hb_buffer_t *buffer)
+ {
+ buffer->reset ();
+ }
+
+ /**
+ * 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: 0.9.11
+ **/
+ void
+ hb_buffer_clear_contents (hb_buffer_t *buffer)
+ {
+ buffer->clear ();
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
+ {
+ return buffer->ensure (size);
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_allocation_successful (hb_buffer_t *buffer)
+ {
+ return !buffer->in_error;
+ }
+
+ /**
+ * 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: 0.9.7
+ **/
+ void
+ hb_buffer_add (hb_buffer_t *buffer,
+ hb_codepoint_t codepoint,
+ unsigned int cluster)
+ {
+ buffer->add (codepoint, cluster);
+ buffer->clear_context (1);
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_bool_t
+ hb_buffer_set_length (hb_buffer_t *buffer,
+ unsigned int length)
+ {
+ if (unlikely (hb_object_is_inert (buffer)))
+@@ -1296,61 +1365,67 @@ hb_buffer_set_length (hb_buffer_t *buff
+ }
+ buffer->clear_context (1);
+
+ return true;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ unsigned int
+ hb_buffer_get_length (hb_buffer_t *buffer)
+ {
+ return buffer->len;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_glyph_info_t *
+ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
+ unsigned int *length)
+ {
+ if (length)
+ *length = buffer->len;
+
+ return (hb_glyph_info_t *) buffer->info;
+ }
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_glyph_position_t *
+ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
+ unsigned int *length)
+ {
+ if (!buffer->have_positions)
+@@ -1359,64 +1434,64 @@ hb_buffer_get_glyph_positions (hb_buffer
+ if (length)
+ *length = buffer->len;
+
+ return (hb_glyph_position_t *) buffer->pos;
+ }
+
+ /**
+ * hb_buffer_reverse:
+- * @buffer: a buffer.
++ * @buffer: an #hb_buffer_t.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_reverse (hb_buffer_t *buffer)
+ {
+ buffer->reverse ();
+ }
+
+ /**
+ * hb_buffer_reverse_range:
+- * @buffer: a buffer.
++ * @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: 0.9.2
+ **/
+ void
+ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
+ {
+ buffer->reverse_clusters ();
+ }
+
+ /**
+ * 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
+ * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ *
+ * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * will be set to the Unicode script of the first character in
+ * the buffer that has a script other than %HB_SCRIPT_COMMON,
+@@ -1505,111 +1580,141 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
+ buffer->context[1][buffer->context_len[1]++] = u;
+ }
+
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
+ }
+
+ /**
+ * hb_buffer_add_utf8:
+- * @buffer: a buffer.
+- * @text: (array length=text_length) (element-type uint8_t):
+- * @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().
++ *
++ * 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,
+ const char *text,
+ int text_length,
+ unsigned int item_offset,
+ int 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().
++ *
++ * 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,
+ const uint16_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int 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().
++ *
++ * 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,
+ const uint32_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length)
+ {
+ hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+ }
+
+ /**
+ * hb_buffer_add_latin1:
+- * @buffer: a buffer.
+- * @text: (array length=text_length) (element-type uint8_t):
+- * @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).
+ *
+- *
++ * 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: 0.9.31
+ **/
+ void
+ hb_buffer_add_codepoints (hb_buffer_t *buffer,
+ const hb_codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+@@ -1671,19 +1776,22 @@ normalize_glyphs_cluster (hb_buffer_t *b
+ pos[i].y_offset -= total_y_advance;
+ }
+ 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.
++ *
++ * <note>This has nothing to do with Unicode normalization.</note>
+ *
+ * Since: 0.9.2
+ **/
+ void
+ hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+ {
+ assert (buffer->have_positions);
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+@@ -1719,8 +1827,50 @@ hb_buffer_t::sort (unsigned int start, u
+ 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 --git a/gfx/harfbuzz/src/hb-buffer.h b/gfx/harfbuzz/src/hb-buffer.h
+--- a/gfx/harfbuzz/src/hb-buffer.h
++++ b/gfx/harfbuzz/src/hb-buffer.h
+@@ -35,344 +35,438 @@
+ #define HB_BUFFER_H
+
+ #include "hb-common.h"
+ #include "hb-unicode.h"
+ #include "hb-font.h"
+
+ 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;
+ uint32_t cluster;
+
+ /*< private >*/
+ hb_var_int_t var1;
+ 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;
+ hb_position_t x_offset;
+ hb_position_t y_offset;
+
+ /*< private >*/
+ 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;
+ hb_language_t language;
+ /*< private >*/
+ void *reserved1;
+ void *reserved2;
+ } hb_segment_properties_t;
+
+ #define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
+ HB_SCRIPT_INVALID, \
+ HB_LANGUAGE_INVALID, \
+ 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 */
+ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
+ 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;
+
+-void
++HB_EXTERN void
+ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
+ hb_buffer_cluster_level_t cluster_level);
+
+-hb_buffer_cluster_level_t
++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);
+
+-void
++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);
+
+-/* Allows only access to first 256 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);
+
+-/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
+-void
++HB_EXTERN void
+ hb_buffer_add_codepoints (hb_buffer_t *buffer,
+ const hb_codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+ 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);
+
+
+ /*
+ * 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_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 --git a/gfx/harfbuzz/src/hb-common.cc b/gfx/harfbuzz/src/hb-common.cc
+--- a/gfx/harfbuzz/src/hb-common.cc
++++ b/gfx/harfbuzz/src/hb-common.cc
+@@ -276,22 +276,25 @@ retry:
+ #endif
+
+ return lang;
+ }
+
+
+ /**
+ * hb_language_from_string:
+- * @str: (array length=len) (element-type uint8_t):
+- * @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: (transfer none):
++ * The #hb_language_t corresponding to the ISO 639 language code.
+ *
+ * Since: 0.9.2
+ **/
+ hb_language_t
+ hb_language_from_string (const char *str, int len)
+ {
+ if (!str || !len || !*str)
+ return HB_LANGUAGE_INVALID;
+@@ -309,21 +312,23 @@ hb_language_from_string (const char *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: 0.9.2
+ **/
+ const char *
+ hb_language_to_string (hb_language_t language)
+ {
+ /* This is actually NULL-safe! */
+ return language->s;
+@@ -352,21 +357,22 @@ hb_language_get_default (void)
+ return default_language;
+ }
+
+
+ /* hb_script_t */
+
+ /**
+ * 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: 0.9.2
+ **/
+ hb_script_t
+ hb_script_from_iso15924_tag (hb_tag_t tag)
+ {
+ if (unlikely (tag == HB_TAG_NONE))
+ return HB_SCRIPT_INVALID;
+@@ -396,38 +402,43 @@ hb_script_from_iso15924_tag (hb_tag_t ta
+ return (hb_script_t) tag;
+
+ /* Otherwise, return unknown */
+ return HB_SCRIPT_UNKNOWN;
+ }
+
+ /**
+ * hb_script_from_string:
+- * @s: (array length=len) (element-type uint8_t):
+- * @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: 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: 0.9.2
+ **/
+ hb_tag_t
+ hb_script_to_iso15924_tag (hb_script_t script)
+ {
+ return (hb_tag_t) script;
+ }
+@@ -516,17 +527,17 @@ hb_user_data_array_t::set (hb_user_data_
+
+ if (replace) {
+ if (!data && !destroy) {
+ items.remove (key, lock);
+ return true;
+ }
+ }
+ 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;
+ }
+
+ void *
+ hb_user_data_array_t::get (hb_user_data_key_t *key)
+ {
+ hb_user_data_item_t item = {NULL };
+diff --git a/gfx/harfbuzz/src/hb-common.h b/gfx/harfbuzz/src/hb-common.h
+--- a/gfx/harfbuzz/src/hb-common.h
++++ b/gfx/harfbuzz/src/hb-common.h
+@@ -93,64 +93,69 @@ typedef uint32_t hb_tag_t;
+ #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
+ #define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
+
+ #define HB_TAG_NONE HB_TAG(0,0,0,0)
+ #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+ #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,
+ HB_DIRECTION_RTL,
+ HB_DIRECTION_TTB,
+ HB_DIRECTION_BTT
+ } 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)
+ /* Direction must be valid for the following */
+ #define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
+ #define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6)
+ #define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4)
+ #define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5)
+ #define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
+
+
+ /* hb_language_t */
+
+ 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);
+
+
+ /* hb_script_t */
+
+ /* http://unicode.org/iso15924/ */
+ /* http://goo.gl/x9ilM */
+ /* Unicode Character Database property: Script (sc) */
+@@ -319,28 +324,26 @@ typedef enum
+ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
+ _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
+
+ } hb_script_t;
+
+
+ /* 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);
+
+
+ /* User data */
+
+ typedef struct hb_user_data_key_t {
+ /*< private >*/
+ char unused;
+diff --git a/gfx/harfbuzz/src/hb-coretext.cc b/gfx/harfbuzz/src/hb-coretext.cc
+--- a/gfx/harfbuzz/src/hb-coretext.cc
++++ b/gfx/harfbuzz/src/hb-coretext.cc
+@@ -171,16 +171,53 @@ hb_coretext_shaper_font_data_t *
+ 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);
++ return NULL;
++ }
++
+ return data;
+ }
+
+ void
+ _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+ {
+ CFRelease (data->ct_font);
+ free (data);
+@@ -688,17 +725,16 @@ resize_and_retry:
+ /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the
+ * cleanest way to do without completely restructuring the rest of this shaper. */
+ scratch = buffer->get_scratch_buffer (&scratch_size);
+ pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
+ log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
+ scratch += old_scratch_used;
+ scratch_size -= old_scratch_used;
+ }
+-retry:
+ {
+ string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+ pchars, chars_len,
+ kCFAllocatorNull);
+ if (unlikely (!string_ref))
+ FAIL ("CFStringCreateWithCharactersNoCopy failed");
+
+ /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
+@@ -843,21 +879,19 @@ retry:
+ *
+ * Looks like if we really want to be sure here we have to modify the
+ * font to change the name table, similar to what we do in the uniscribe
+ * backend.
+ *
+ * However, even that wouldn't work if we were passed in the CGFont to
+ * 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
+ */
+ bool matched = false;
+ for (unsigned int i = 0; i < range_records.len; i++)
+ if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
+ {
+ matched = true;
+@@ -1124,20 +1158,16 @@ fail:
+ return ret;
+ }
+
+
+ /*
+ * AAT shaper
+ */
+
+-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+-
+-
+ /*
+ * shaper face data
+ */
+
+ struct hb_coretext_aat_shaper_face_data_t {};
+
+ hb_coretext_aat_shaper_face_data_t *
+ _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
+diff --git a/gfx/harfbuzz/src/hb-coretext.h b/gfx/harfbuzz/src/hb-coretext.h
+--- a/gfx/harfbuzz/src/hb-coretext.h
++++ b/gfx/harfbuzz/src/hb-coretext.h
+@@ -39,22 +39,22 @@
+
+ HB_BEGIN_DECLS
+
+
+ #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+ #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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_CORETEXT_H */
+diff --git a/gfx/harfbuzz/src/hb-directwrite.cc b/gfx/harfbuzz/src/hb-directwrite.cc
+new file mode 100644
+--- /dev/null
++++ b/gfx/harfbuzz/src/hb-directwrite.cc
+@@ -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 --git a/gfx/harfbuzz/src/hb-directwrite.h b/gfx/harfbuzz/src/hb-directwrite.h
+new file mode 100644
+--- /dev/null
++++ b/gfx/harfbuzz/src/hb-directwrite.h
+@@ -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 --git a/gfx/harfbuzz/src/hb-face.h b/gfx/harfbuzz/src/hb-face.h
+--- a/gfx/harfbuzz/src/hb-face.h
++++ b/gfx/harfbuzz/src/hb-face.h
+@@ -38,80 +38,80 @@ HB_BEGIN_DECLS
+
+
+ /*
+ * hb_face_t
+ */
+
+ 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,
+ hb_destroy_func_t destroy,
+ 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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_FACE_H */
+diff --git a/gfx/harfbuzz/src/hb-fallback-shape.cc b/gfx/harfbuzz/src/hb-fallback-shape.cc
+--- a/gfx/harfbuzz/src/hb-fallback-shape.cc
++++ b/gfx/harfbuzz/src/hb-fallback-shape.cc
+@@ -101,17 +101,17 @@ hb_bool_t
+ * - Handle Variation Selectors?
+ * - Apply normalization?
+ *
+ * This will make the fallback shaper into a dumb "TrueType"
+ * shaper which many people unfortunately still request.
+ */
+
+ hb_codepoint_t space;
+- bool has_space = font->get_glyph (' ', 0, &space);
++ bool has_space = (bool) font->get_glyph (' ', 0, &space);
+
+ buffer->clear_positions ();
+
+ hb_direction_t direction = buffer->props.direction;
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+diff --git a/gfx/harfbuzz/src/hb-font-private.hh b/gfx/harfbuzz/src/hb-font-private.hh
+--- a/gfx/harfbuzz/src/hb-font-private.hh
++++ b/gfx/harfbuzz/src/hb-font-private.hh
+@@ -37,16 +37,18 @@
+
+
+
+ /*
+ * hb_font_funcs_t
+ */
+
+ #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) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
+ HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
+@@ -75,17 +77,17 @@ struct hb_font_funcs_t {
+
+ /* Don't access these directly. Call font->get_*() instead. */
+ union get_t {
+ struct get_funcs_t {
+ #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+ #undef HB_FONT_FUNC_IMPLEMENT
+ } f;
+- void (*array[]) (void);
++ void (*array[VAR]) (void);
+ } get;
+ };
+
+
+
+ /*
+ * hb_font_t
+ */
+@@ -155,17 +157,32 @@ struct hb_font_t {
+ { \
+ 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 has_glyph (hb_codepoint_t unicode)
++ 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);
+ }
+
+ inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph)
+ {
+@@ -260,16 +277,36 @@ struct hb_font_t {
+ 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)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+ *x = get_glyph_h_advance (glyph);
+ *y = 0;
+ } else {
+@@ -279,17 +316,17 @@ struct hb_font_t {
+ }
+
+ /* Internal only */
+ inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = get_glyph_h_advance (glyph) / 2;
+
+- /* TODO use font_metrics.ascent */
++ /* TODO use font_extents.ascender */
+ *y = y_scale;
+ }
+
+ inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+diff --git a/gfx/harfbuzz/src/hb-font.cc b/gfx/harfbuzz/src/hb-font.cc
+--- a/gfx/harfbuzz/src/hb-font.cc
++++ b/gfx/harfbuzz/src/hb-font.cc
+@@ -40,16 +40,64 @@
+ #include <string.h>
+
+
+ /*
+ * hb_font_funcs_t
+ */
+
+ static hb_bool_t
++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)
+ {
+ *glyph = 0;
+@@ -104,17 +152,17 @@ static hb_bool_t
+ 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)
+ {
+ *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)
+@@ -275,17 +323,16 @@ hb_font_get_glyph_from_name_parent (hb_f
+ 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,
+
+ true, /* immutable */
+
+ {
+ #define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+@@ -517,16 +564,52 @@ 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:
+ * @variation_selector:
+ * @glyph: (out):
+ *
+ *
+ *
+@@ -741,16 +824,33 @@ hb_font_get_glyph_from_name (hb_font_t *
+ {
+ return font->get_glyph_from_name (name, len, glyph);
+ }
+
+
+ /* 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:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+diff --git a/gfx/harfbuzz/src/hb-font.h b/gfx/harfbuzz/src/hb-font.h
+--- a/gfx/harfbuzz/src/hb-font.h
++++ b/gfx/harfbuzz/src/hb-font.h
+@@ -41,61 +41,85 @@ typedef struct hb_font_t hb_font_t;
+
+
+ /*
+ * hb_font_funcs_t
+ */
+
+ 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,
+ hb_destroy_func_t destroy,
+ 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; /* 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 */
+
+-/* 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,
+ void *user_data);
+
+
+ typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
+@@ -136,377 +160,419 @@ typedef hb_bool_t (*hb_font_get_glyph_fr
+ const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph,
+ void *user_data);
+
+
+ /* 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):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_h_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_v_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_h_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_v_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_v_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_contour_point_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+ /**
+ * hb_font_funcs_set_glyph_from_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * 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);
+
+
+ /* 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);
+
+
+ /*
+ * hb_font_t
+ */
+
+ /* 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,
+ hb_destroy_func_t destroy,
+ 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);
+
+-void
++HB_EXTERN void
+ hb_font_set_parent (hb_font_t *font,
+ hb_font_t *parent);
+
+-hb_font_t *
++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);
+
+ /*
+ * 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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_FONT_H */
+diff --git a/gfx/harfbuzz/src/hb-ft.cc b/gfx/harfbuzz/src/hb-ft.cc
+--- a/gfx/harfbuzz/src/hb-ft.cc
++++ b/gfx/harfbuzz/src/hb-ft.cc
+@@ -361,16 +361,35 @@ hb_ft_get_glyph_from_name (hb_font_t *fo
+ if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
+ len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+ return true;
+ }
+
+ 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);
+@@ -382,16 +401,18 @@ static void
+ {
+ 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);
+diff --git a/gfx/harfbuzz/src/hb-ft.h b/gfx/harfbuzz/src/hb-ft.h
+--- a/gfx/harfbuzz/src/hb-ft.h
++++ b/gfx/harfbuzz/src/hb-ft.h
+@@ -54,73 +54,73 @@ HB_BEGIN_DECLS
+ * 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_face_t *
++HB_EXTERN hb_face_t *
+ hb_ft_face_create (FT_Face ft_face,
+ hb_destroy_func_t destroy);
+
+ /* 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_face_t *
++HB_EXTERN hb_face_t *
+ hb_ft_face_create_cached (FT_Face ft_face);
+
+ /* 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_face_t *
++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_font_t *
++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_font_t *
++HB_EXTERN hb_font_t *
+ hb_ft_font_create_referenced (FT_Face ft_face);
+
+-FT_Face
++HB_EXTERN FT_Face
+ hb_ft_font_get_face (hb_font_t *font);
+
+-void
++HB_EXTERN void
+ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
+
+-int
++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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_FT_H */
+diff --git a/gfx/harfbuzz/src/hb-glib.cc b/gfx/harfbuzz/src/hb-glib.cc
+--- a/gfx/harfbuzz/src/hb-glib.cc
++++ b/gfx/harfbuzz/src/hb-glib.cc
+@@ -378,16 +378,18 @@ hb_glib_get_unicode_funcs (void)
+ #undef HB_UNICODE_FUNC_IMPLEMENT
+ }
+ };
+
+ 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,
+diff --git a/gfx/harfbuzz/src/hb-glib.h b/gfx/harfbuzz/src/hb-glib.h
+--- a/gfx/harfbuzz/src/hb-glib.h
++++ b/gfx/harfbuzz/src/hb-glib.h
+@@ -31,25 +31,25 @@
+
+ #include "hb.h"
+
+ #include <glib.h>
+
+ 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_blob_t *
++HB_EXTERN hb_blob_t *
+ hb_glib_blob_create (GBytes *gbytes);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_GLIB_H */
+diff --git a/gfx/harfbuzz/src/hb-gobject-enums.h.tmpl b/gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
+--- a/gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
++++ b/gfx/harfbuzz/src/hb-gobject-enums.h.tmpl
+@@ -37,17 +37,17 @@
+ #include <glib-object.h>
+
+ HB_BEGIN_DECLS
+
+
+ /*** 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 ***/
+
+ /*** BEGIN file-tail ***/
+
+ HB_END_DECLS
+
+diff --git a/gfx/harfbuzz/src/hb-gobject-structs.h b/gfx/harfbuzz/src/hb-gobject-structs.h
+--- a/gfx/harfbuzz/src/hb-gobject-structs.h
++++ b/gfx/harfbuzz/src/hb-gobject-structs.h
+@@ -38,68 +38,68 @@
+ HB_BEGIN_DECLS
+
+
+ /* Object types */
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_blob_get_type (void);
++HB_EXTERN GType hb_gobject_blob_get_type (void);
+ #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_buffer_get_type (void);
++HB_EXTERN GType hb_gobject_buffer_get_type (void);
+ #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_face_get_type (void);
++HB_EXTERN GType hb_gobject_face_get_type (void);
+ #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_font_get_type (void);
++HB_EXTERN GType hb_gobject_font_get_type (void);
+ #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_font_funcs_get_type (void);
++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 ())
+
+ /**
+ * Since: 0.9.2
+ **/
+-GType hb_gobject_unicode_funcs_get_type (void);
++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 ())
+
+
+ HB_END_DECLS
+
+ #endif /* HB_GOBJECT_H */
+diff --git a/gfx/harfbuzz/src/hb-graphite2.cc b/gfx/harfbuzz/src/hb-graphite2.cc
+--- a/gfx/harfbuzz/src/hb-graphite2.cc
++++ b/gfx/harfbuzz/src/hb-graphite2.cc
+@@ -346,27 +346,28 @@ hb_bool_t
+ {
+ hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
+ info->codepoint = gids[clusters[i].base_glyph + j];
+ info->cluster = clusters[i].cluster;
+ }
+ }
+ buffer->len = glyph_count;
+
++ 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) - curradvy;
++ 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);
++ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
+ curradvx += pPos->x_advance;
+ curradvy += pPos->y_advance;
+ }
+ pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+ }
+ else
+ {
+ hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL) + buffer->len - 1;
+@@ -382,27 +383,27 @@ hb_bool_t
+ 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);
++ 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);
++ 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) - curradvy;
++ 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);
+
+ return true;
+diff --git a/gfx/harfbuzz/src/hb-graphite2.h b/gfx/harfbuzz/src/hb-graphite2.h
+--- a/gfx/harfbuzz/src/hb-graphite2.h
++++ b/gfx/harfbuzz/src/hb-graphite2.h
+@@ -31,18 +31,18 @@
+ #include <graphite2/Font.h>
+
+ HB_BEGIN_DECLS
+
+
+ #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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_GRAPHITE2_H */
+diff --git a/gfx/harfbuzz/src/hb-icu.h b/gfx/harfbuzz/src/hb-icu.h
+--- a/gfx/harfbuzz/src/hb-icu.h
++++ b/gfx/harfbuzz/src/hb-icu.h
+@@ -31,22 +31,22 @@
+
+ #include "hb.h"
+
+ #include <unicode/uscript.h>
+
+ 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);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_ICU_H */
+diff --git a/gfx/harfbuzz/src/hb-open-type-private.hh b/gfx/harfbuzz/src/hb-open-type-private.hh
+--- a/gfx/harfbuzz/src/hb-open-type-private.hh
++++ b/gfx/harfbuzz/src/hb-open-type-private.hh
+@@ -98,19 +98,16 @@ static inline Type& StructAfter(TObject
+ # define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
+
+
+ #define DEFINE_SIZE_STATIC(size) \
+ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
+ 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)
+
+ #define DEFINE_SIZE_MIN(size) \
+ DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
+ static const unsigned int min_size = (size)
+
+@@ -180,17 +177,17 @@ struct hb_dispatch_context_t
+
+ #define TRACE_SANITIZE(this) \
+ hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
+
+ /* This limits sanitizing time on really broken fonts. */
+ #ifndef HB_SANITIZE_MAX_EDITS
+-#define HB_SANITIZE_MAX_EDITS 8
++#define HB_SANITIZE_MAX_EDITS 32
+ #endif
+
+ 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),
+diff --git a/gfx/harfbuzz/src/hb-ot-font.cc b/gfx/harfbuzz/src/hb-ot-font.cc
+--- a/gfx/harfbuzz/src/hb-ot-font.cc
++++ b/gfx/harfbuzz/src/hb-ot-font.cc
+@@ -30,34 +30,63 @@
+
+ #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
+ {
+ 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)
++ hb_tag_t _hea_tag,
++ hb_tag_t _mtx_tag,
++ hb_tag_t os2_tag)
+ {
+ 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));
+
+ /* 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;
+@@ -247,18 +276,18 @@ static hb_ot_font_t *
+ _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));
+
+ if (unlikely (!ot_font))
+ return NULL;
+
+ ot_font->cmap.init (face);
+- ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx);
+- ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx); /* 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;
+ }
+
+ static void
+ _hb_ot_font_destroy (hb_ot_font_t *ot_font)
+ {
+@@ -315,16 +344,41 @@ hb_ot_get_glyph_extents (hb_font_t *font
+ 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_font_h_extents (hb_font_t *font HB_UNUSED,
++ void *font_data,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ 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_font_v_extents (hb_font_t *font HB_UNUSED,
++ void *font_data,
++ hb_font_extents_t *metrics,
++ void *user_data HB_UNUSED)
++{
++ 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_font_funcs_t *static_ot_funcs = NULL;
+
+ #ifdef HB_USE_ATEXIT
+ static
+ void free_static_ot_funcs (void)
+ {
+ hb_font_funcs_destroy (static_ot_funcs);
+@@ -336,16 +390,18 @@ static hb_font_funcs_t *
+ {
+ retry:
+ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
+
+ if (unlikely (!funcs))
+ {
+ funcs = hb_font_funcs_create ();
+
++ 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);
+@@ -365,16 +421,18 @@ retry:
+ #endif
+ };
+
+ 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->face);
+ if (unlikely (!ot_font))
+ return;
+diff --git a/gfx/harfbuzz/src/hb-ot-font.h b/gfx/harfbuzz/src/hb-ot-font.h
+--- a/gfx/harfbuzz/src/hb-ot-font.h
++++ b/gfx/harfbuzz/src/hb-ot-font.h
+@@ -31,15 +31,15 @@
+ #ifndef HB_OT_FONT_H
+ #define HB_OT_FONT_H
+
+ #include "hb.h"
+
+ HB_BEGIN_DECLS
+
+
+-void
++HB_EXTERN void
+ hb_ot_font_set_funcs (hb_font_t *font);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_OT_FONT_H */
+diff --git a/gfx/harfbuzz/src/hb-ot-head-table.hh b/gfx/harfbuzz/src/hb-ot-head-table.hh
+--- a/gfx/harfbuzz/src/hb-ot-head-table.hh
++++ b/gfx/harfbuzz/src/hb-ot-head-table.hh
+@@ -50,17 +50,19 @@ struct head
+ 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) const
+ {
+ TRACE_SANITIZE (this);
+- return_trace (c->check_struct (this) && likely (version.major == 1));
++ return_trace (c->check_struct (this) &&
++ version.major == 1 &&
++ magicNumber == 0x5F0F3CF5u);
+ }
+
+ protected:
+ FixedVersion version; /* Version of the head table--currently
+ * 0x00010000u for version 1.0. */
+ FixedVersion fontRevision; /* Set by font manufacturer. */
+ ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
+ * entire font as ULONG, then store
+diff --git a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
+@@ -540,16 +540,19 @@ struct Feature
+
+ OffsetTo<FeatureParams> new_offset;
+ /* Check that it did not overflow. */
+ new_offset.set (new_offset_int);
+ if (new_offset == new_offset_int &&
+ c->try_set (&featureParams, new_offset) &&
+ !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+ return_trace (false);
++
++ if (c->edit_count > 1)
++ c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
+ }
+
+ return_trace (true);
+ }
+
+ OffsetTo<FeatureParams>
+ featureParams; /* Offset to Feature Parameters table (if one
+ * has been defined for the feature), relative
+diff --git a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
++++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
+@@ -737,17 +737,17 @@ struct PairPosFormat1
+ DEFINE_SIZE_ARRAY (10, pairSet);
+ };
+
+ struct PairPosFormat2
+ {
+ 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;
+ for (unsigned int i = 0; i < count1; i++)
+ klass1.add_class (c->input, i);
+
+ unsigned int count2 = class2Count;
+ const ClassDef &klass2 = this+classDef2;
+diff --git a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
+@@ -840,37 +840,43 @@ static inline bool ligate_input (hb_appl
+ }
+ c->replace_glyph_with_ligature (lig_glyph, klass);
+
+ for (unsigned int i = 1; i < count; 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 ();
+ }
+
+ last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+ components_so_far += last_num_components;
+
+ /* Skip the base glyph */
+ buffer->idx++;
+ }
+
+ if (!is_mark_ligature && last_lig_id) {
+ /* 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;
+ }
+ }
+ return_trace (true);
+ }
+
+@@ -966,16 +972,21 @@ static inline bool apply_lookup (hb_appl
+ }
+
+ for (unsigned int i = 0; i < lookupCount; i++)
+ {
+ unsigned int idx = lookupRecord[i].sequenceIndex;
+ 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 ();
+ if (!c->recurse (lookupRecord[i].lookupListIndex))
+ continue;
+
+ unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
+ int delta = new_len - orig_len;
+diff --git a/gfx/harfbuzz/src/hb-ot-layout-private.hh b/gfx/harfbuzz/src/hb-ot-layout-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
+@@ -512,21 +512,19 @@ static inline bool
+ static inline void
+ _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
+ {
+ info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+ }
+
+ static inline void
+-_hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *info)
++_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
+ {
+- info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+- HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+- HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
++ info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+ }
+
+
+ /* Allocation / deallocation. */
+
+ static inline void
+ _hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+ {
+diff --git a/gfx/harfbuzz/src/hb-ot-layout.cc b/gfx/harfbuzz/src/hb-ot-layout.cc
+--- a/gfx/harfbuzz/src/hb-ot-layout.cc
++++ b/gfx/harfbuzz/src/hb-ot-layout.cc
+@@ -125,26 +125,30 @@ static inline const OT::GPOS&
+
+ hb_bool_t
+ hb_ot_layout_has_glyph_classes (hb_face_t *face)
+ {
+ 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)
+ {
+ 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,
+ hb_set_t *glyphs /* OUT */)
+ {
+ return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
+@@ -360,16 +364,18 @@ hb_ot_layout_language_get_required_featu
+ table_tag,
+ script_index,
+ language_index,
+ feature_index,
+ 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,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index,
+@@ -447,16 +453,18 @@ hb_ot_layout_language_find_feature (hb_f
+ }
+ }
+
+ if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
+ 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,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+@@ -464,16 +472,18 @@ hb_ot_layout_feature_get_lookups (hb_fac
+ {
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::Feature &f = g.get_feature (feature_index);
+
+ 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)
+ {
+ switch (table_tag)
+ {
+@@ -624,16 +634,18 @@ static void
+ language_index,
+ features,
+ lookup_indexes);
+ }
+ }
+ }
+
+ /**
++ * hb_ot_layout_collect_lookups:
++ *
+ * Since: 0.9.8
+ **/
+ void
+ hb_ot_layout_collect_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *scripts,
+ const hb_tag_t *languages,
+ const hb_tag_t *features,
+@@ -668,16 +680,18 @@ hb_ot_layout_collect_lookups (hb_face_t
+ languages,
+ features,
+ lookup_indexes);
+ }
+ }
+ }
+
+ /**
++ * 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,
+ unsigned int lookup_index,
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+@@ -716,16 +730,18 @@ hb_ot_layout_lookup_collect_glyphs (hb_f
+
+ hb_bool_t
+ hb_ot_layout_has_substitution (hb_face_t *face)
+ {
+ 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,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context)
+@@ -737,17 +753,17 @@ hb_ot_layout_lookup_would_substitute (hb
+ hb_bool_t
+ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ 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]);
+ }
+
+ void
+ hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
+@@ -757,16 +773,18 @@ hb_ot_layout_substitute_start (hb_font_t
+
+ void
+ hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
+ {
+ 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,
+ hb_set_t *glyphs)
+ {
+ OT::hb_closure_context_t c (face, glyphs);
+@@ -794,16 +812,18 @@ hb_ot_layout_position_start (hb_font_t *
+
+ void
+ hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+ {
+ 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 */
+ unsigned int *subfamily_id, /* OUT. May be NULL */
+ unsigned int *subfamily_name_id, /* OUT. May be NULL */
+ unsigned int *range_start, /* OUT. May be NULL */
+@@ -1003,35 +1023,25 @@ inline void hb_ot_map_t::apply (const Pr
+ unsigned int i = 0;
+ OT::hb_apply_context_t c (table_index, font, buffer);
+ c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+ for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+ const stage_map_t *stage = &stages[table_index][stage_index];
+ for (; i < stage->last_lookup; i++)
+ {
+-#if 0
+- char buf[4096];
+- hb_buffer_serialize_glyphs (buffer, 0, buffer->len,
+- buf, sizeof (buf), NULL,
+- font,
+- HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+- Proxy::table_index == 0 ?
+- HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS :
+- HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+- printf ("buf: [%s]\n", buf);
+-#endif
+-
+ 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)
+ {
+ buffer->clear_output ();
+ stage->pause_func (plan, font, buffer);
+ }
+ }
+diff --git a/gfx/harfbuzz/src/hb-ot-layout.h b/gfx/harfbuzz/src/hb-ot-layout.h
+--- a/gfx/harfbuzz/src/hb-ot-layout.h
++++ b/gfx/harfbuzz/src/hb-ot-layout.h
+@@ -43,170 +43,170 @@ HB_BEGIN_DECLS
+ #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+ #define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
+
+
+ /*
+ * GDEF
+ */
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_ot_layout_has_glyph_classes (hb_face_t *face);
+
+ typedef enum {
+ HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0,
+ HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 1,
+ HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 2,
+ HB_OT_LAYOUT_GLYPH_CLASS_MARK = 3,
+ 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 */);
+
+
+ /* 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,
+ unsigned int *point_count /* IN/OUT */,
+ 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,
+ unsigned int start_offset,
+ unsigned int *caret_count /* IN/OUT */,
+ hb_position_t *caret_array /* OUT */);
+
+
+ /*
+ * GSUB/GPOS feature query and enumeration interface
+ */
+
+ #define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
+ #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,
+ unsigned int start_offset,
+ 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,
+ unsigned int language_index,
+ 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,
+ unsigned int language_index,
+ unsigned int start_offset,
+ 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,
+ unsigned int language_index,
+ unsigned int start_offset,
+ 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,
+ unsigned int language_index,
+ 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,
+ unsigned int start_offset,
+ 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,
+ const hb_tag_t *languages,
+ 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,
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ 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 */);
+
+@@ -223,77 +223,77 @@ typedef struct
+
+ typedef hb_bool_t
+ (*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+ 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,
+ hb_ot_layout_glyph_sequence_func_t callback,
+ void *user_data);
+ #endif
+
+
+ /*
+ * 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
+ /*TODO , hb_bool_t inclusive */);
+
+ #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,
+ unsigned int out_size,
+ hb_codepoint_t *glyphs_out, /* OUT */
+ unsigned int *clusters_out, /* OUT */
+ unsigned int *out_length /* OUT */);
+ #endif
+
+
+ /*
+ * 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,
+ hb_glyph_position_t *positions /* IN / OUT */);
+ #endif
+
+ /* 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 */
+ unsigned int *subfamily_name_id, /* OUT. May be NULL */
+ unsigned int *range_start, /* OUT. May be NULL */
+ unsigned int *range_end /* OUT. May be NULL */);
+
+
+diff --git a/gfx/harfbuzz/src/hb-ot-map-private.hh b/gfx/harfbuzz/src/hb-ot-map-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-map-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-map-private.hh
+@@ -198,17 +198,18 @@ struct hb_ot_map_builder_t
+ hb_tag_t tag;
+ unsigned int seq; /* sequence#, used for stable sorting only */
+ unsigned int max_value;
+ hb_ot_map_feature_flags_t flags;
+ unsigned int default_value; /* for non-global features, what should the unset glyphs take */
+ 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 {
+ unsigned int index;
+ hb_ot_map_t::pause_func_t pause_func;
+ };
+
+ HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
+diff --git a/gfx/harfbuzz/src/hb-ot-map.cc b/gfx/harfbuzz/src/hb-ot-map.cc
+--- a/gfx/harfbuzz/src/hb-ot-map.cc
++++ b/gfx/harfbuzz/src/hb-ot-map.cc
+@@ -84,17 +84,17 @@ hb_ot_map_builder_t::hb_ot_map_builder_t
+ hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
+ hb_tag_t language_tag;
+
+ hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
+ language_tag = hb_ot_tag_from_language (props.language);
+
+ 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]);
+ }
+ }
+
+ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
+ hb_ot_map_feature_flags_t flags)
+ {
+ feature_info_t *info = feature_infos.push();
+diff --git a/gfx/harfbuzz/src/hb-ot-os2-table.hh b/gfx/harfbuzz/src/hb-ot-os2-table.hh
+new file mode 100644
+--- /dev/null
++++ b/gfx/harfbuzz/src/hb-ot-os2-table.hh
+@@ -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 --git a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+@@ -218,26 +218,26 @@ collect_features_arabic (hb_ot_shape_pla
+ map->add_gsub_pause (NULL);
+ }
+
+ map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
+ if (plan->props.script == HB_SCRIPT_ARABIC)
+ 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
+ * that Windows 8 and later do not enable it by default,
+ * and spec now says 'Off by default'.
+ * We disabled this in ae23c24c32.
+ * 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'));
+ }
+
+ #include "hb-ot-shape-complex-arabic-fallback.hh"
+
+ struct arabic_shape_plan_t
+ {
+@@ -458,20 +458,16 @@ apply_stch (const hb_ot_shape_plan_t *pl
+ * 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.
+ */
+
+- /* 30 = 2048 / 70.
+- * https://www.microsoft.com/typography/cursivescriptguidelines.mspx */
+- hb_position_t overlap = font->x_scale / 30;
+- DEBUG_MSG (ARABIC, NULL, "overlap for stretching is %d", overlap);
+ 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;
+@@ -499,28 +495,25 @@ apply_stch (const hb_ot_shape_plan_t *pl
+ 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_glyph_extents_t extents;
+- if (!font->get_glyph_extents (info[i].codepoint, &extents))
+- extents.width = 0;
+- extents.width -= overlap;
++ hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
+ if (info[i].arabic_shaping_action() == STCH_FIXED)
+ {
+- w_fixed += extents.width;
++ w_fixed += width;
+ n_fixed++;
+ }
+ else
+ {
+- w_repeating += extents.width;
++ 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]) ||
+@@ -535,44 +528,54 @@ apply_stch (const hb_ot_shape_plan_t *pl
+ 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 - overlap;
++ 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 / 4) / (sign * w_repeating) - 1;
++ 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 = -overlap;
++ hb_position_t x_offset = 0;
+ for (unsigned int k = end; k > start; k--)
+ {
+- hb_glyph_extents_t extents;
+- if (!font->get_glyph_extents (info[k - 1].codepoint, &extents))
+- extents.width = 0;
+- extents.width -= overlap;
++ 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 -= extents.width;
++ 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];
+ }
+ }
+ }
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc
+@@ -35,11 +35,11 @@ const hb_ot_complex_shaper_t _hb_ot_comp
+ 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 --git a/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-hebrew.cc
+@@ -63,17 +63,17 @@ compose_hebrew (const hb_ot_shape_normal
+ 0x0000u, /* FINAL TSADI */
+ 0xFB46u, /* TSADI */
+ 0xFB47u, /* QOF */
+ 0xFB48u, /* RESH */
+ 0xFB49u, /* SHIN */
+ 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)
+ {
+ /* Special-case Hebrew presentation forms that are excluded from
+ * standard normalization, but wanted for old fonts. */
+ switch (b) {
+ case 0x05B4u: /* HIRIQ */
+ if (a == 0x05D9u) { /* YOD */
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-private.hh
+@@ -104,37 +104,41 @@ enum indic_position_t {
+ };
+
+ /* Categories used in IndicSyllabicCategory.txt from UCD. */
+ enum indic_syllabic_category_t {
+ INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
+
+ INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
+ INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
+- INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */
+ INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
++ INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_Repha, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
+- INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
+ INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
+ INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
+ INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
+- INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
+- INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
++ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
++ INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
+ INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
++ INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_M, /* Misc Khmer signs. */
+ INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
+ INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
+ INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
+ INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
+ INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
+ INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
+ };
+@@ -157,24 +161,30 @@ enum indic_matra_category_t {
+ INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+ INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+
+ INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
+ INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
+ };
+
+ #define INDIC_COMBINE_CATEGORIES(S,M) \
+- (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
+- ( \
+- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+- S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+- S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+- S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+- S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+- false)) + \
+- ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+- ((M << 8) | S))
++ ( \
++ ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
++ ( S | \
++ ( \
++ ( \
++ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
++ S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
++ S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
++ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
++ S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
++ S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
++ false \
++ ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
++ ) << 8 \
++ ) \
++ ) \
++ )
+
+ HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+ hb_indic_get_categories (hb_codepoint_t u);
+
+ #endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
+@@ -1,315 +1,323 @@
+ /* == Start of generated table == */
+ /*
+ * The following table is generated by running:
+ *
+ * ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
+ *
+ * on files with these headers:
+ *
+- * # IndicSyllabicCategory-7.0.0.txt
+- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+- * # IndicMatraCategory-7.0.0.txt
+- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+- * # Blocks-7.0.0.txt
+- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
++ * # IndicSyllabicCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # IndicPositionalCategory-8.0.0.txt
++ * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
++ * # Blocks-8.0.0.txt
++ * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ */
+
+ #include "hb-ot-shape-complex-indic-private.hh"
+
+
+ #define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 13 chars; Avagraha */
+-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 59 chars; Bindu */
++#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 60 chars; Bindu */
+ #define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
+-#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 30 chars; Cantillation_Mark */
+-#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1744 chars; Consonant */
++#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 52 chars; Cantillation_Mark */
++#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1805 chars; Consonant */
+ #define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 7 chars; Consonant_Dead */
+-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 61 chars; Consonant_Final */
++#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 62 chars; Consonant_Final */
+ #define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
+-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 19 chars; Consonant_Medial */
+-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 11 chars; Consonant_Placeholder */
++#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
++#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 22 chars; Consonant_Medial */
++#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 13 chars; Consonant_Placeholder */
+ #define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 1 chars; Consonant_Preceding_Repha */
++#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 2 chars; Consonant_Prefixed */
+ #define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 61 chars; Consonant_Subjoined */
+ #define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
++#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 4 chars; Consonant_With_Stacker */
+ #define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 2 chars; Gemination_Mark */
+ #define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 7 chars; Invisible_Stacker */
+ #define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
+ #define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
+ #define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
+-#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 18 chars; Nukta */
+-#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 408 chars; Number */
++#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 23 chars; Nukta */
++#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 420 chars; Number */
+ #define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
+ #define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
+-#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 15 chars; Pure_Killer */
+-#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 3 chars; Register_Shifter */
++#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 16 chars; Pure_Killer */
++#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
++#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 20 chars; Syllable_Modifier */
+ #define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
+-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 62 chars; Tone_Mark */
++#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */
+ #define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 22 chars; Virama */
+ #define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 29 chars; Visarga */
+ #define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
+-#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 553 chars; Vowel_Dependent */
+-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 395 chars; Vowel_Independent */
++#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 572 chars; Vowel_Dependent */
++#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 404 chars; Vowel_Independent */
+
+-#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 142 chars; Bottom */
++#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 256 chars; Bottom */
+ #define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */
+-#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 57 chars; Left */
++#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 55 chars; Left */
+ #define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 21 chars; Left_And_Right */
+ #define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
+-#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */
+-#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 163 chars; Right */
+-#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 169 chars; Top */
++#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */
++#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 249 chars; Right */
++#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 324 chars; Top */
+ #define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
+ #define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
+ #define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */
+ #define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
+ #define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
+-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 15 chars; Visual_Order_Left */
++#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */
+
+ #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
+
+
+ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
+
+
+ #define indic_offset_0x0028u 0
+
+
+ /* Basic Latin */
+
+ /* 0028 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x), _(x,x),
+ /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x00d0u 24
++#define indic_offset_0x00b0u 24
+
+
+ /* Latin-1 Supplement */
+
++ /* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
+
+-#define indic_offset_0x0900u 32
++#define indic_offset_0x0900u 64
+
+
+ /* Devanagari */
+
+- /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
+ /* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
+- /* 0950 */ _(x,x), _(TM,x), _(TM,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
++ /* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B),
+ /* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0978 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+
+ /* Bengali */
+
+- /* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0980 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
+- /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
+ /* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
+ /* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
+ /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Gurmukhi */
+
+- /* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
+ /* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
+- /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(x,x), _(M,R), _(M,L),
++ /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L),
+ /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
+ /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
+ /* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
+ /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 0A70 */ _(Bi,x), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
++ /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x),
+ /* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Gujarati */
+
+- /* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
+ /* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
++ /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
+ /* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
+ /* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
+ /* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0AF8 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Oriya */
+
+- /* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
++ /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
+ /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
+ /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
+ /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR),
+ /* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
+ /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Tamil */
+
+- /* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
+ /* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
+ /* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
+ /* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
+ /* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
+- /* 0BC0 */ _(M,T), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
++ /* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
+ /* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
+ /* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Telugu */
+
+- /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(A,x), _(M,T), _(M,T),
+ /* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
+ /* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
+ /* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
+- /* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Kannada */
+
+- /* 0C80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0C80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+- /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
++ /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
+ /* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
+ /* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
+ /* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
+ /* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
+ /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Malayalam */
+
+- /* 0D00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0D00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
+ /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0D38 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(A,x), _(M,R), _(M,R),
+ /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
+ /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,x), _(x,x),
+ /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+- /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
+ /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
+
+ /* Sinhala */
+
+- /* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 0D80 */ _(x,x), _(x,x), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
+ /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x),
+ /* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
+ /* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x),
+ /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR),_(M,TLR), _(M,LR), _(M,R),
+ /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1000u 1304
++#define indic_offset_0x1000u 1336
+
+
+ /* Myanmar */
+
+ /* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
+- /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x),
+- /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
++ /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B),
++ /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B), _(C,x),
+ /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x),
+ /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
+- /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x),
+- /* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R),
+- /* 1068 */ _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
++ /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,B), _(CM,B),
++ /* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R),
++ /* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x),
+ /* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
+ /* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x),
+- /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x),
++ /* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R),
++ /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R),
+ /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+- /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
++ /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x),
+
+-#define indic_offset_0x1700u 1464
++#define indic_offset_0x1700u 1496
+
+
+ /* Tagalog */
+
+ /* 1700 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
+ /* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(PK,B), _(x,x), _(x,x), _(x,x),
+ /* 1718 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+@@ -340,36 +348,36 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
+ /* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
+- /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
+- /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T), _(M,T), _(M,T), _(M,T),
+- /* 17D0 */ _(M,T), _(PK,T), _(IS,x), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x),
++ /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
++ /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
++ /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,T), _(x,x), _(x,x),
+ /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1900u 1704
++#define indic_offset_0x1900u 1736
+
+
+ /* Limbu */
+
+ /* 1900 */ _(CP,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1908 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
+ /* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T),
+- /* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1928 */ _(M,T), _(CS,R), _(CS,R), _(CS,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1930 */ _(CF,R), _(CF,R), _(Bi,B), _(CF,R), _(CF,R), _(CF,R), _(CF,R), _(CF,R),
++ /* 1938 */ _(CF,R), _(CF,B), _(M,T), _(SM,B), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+
+ /* Tai Le */
+
+ /* 1950 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1960 */ _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
+@@ -380,20 +388,20 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* New Tai Lue */
+
+ /* 1980 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1988 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 19A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 19A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,L), _(M,L), _(M,L),
+- /* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
++ /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),_(M,VOL),_(M,VOL),_(M,VOL),
++ /* 19B8 */ _(M,R), _(M,R),_(M,VOL), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
+ /* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 19C8 */ _(TM,R), _(TM,R), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 19D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 19F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Buginese */
+@@ -406,110 +414,120 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* Tai Tham */
+
+ /* 1A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x),
+- /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,x), _(CF,x),
+- /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x),
++ /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,B), _(CF,R),
++ /* 1A58 */ _(CF,T), _(CF,T), _(CF,T), _(CF,B), _(CF,B), _(CF,B), _(CF,B), _(x,x),
+ /* 1A60 */ _(IS,x), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
+ /* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L),
+- /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x),
+- /* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,T), _(TM,T), _(TM,T),
++ /* 1A78 */ _(TM,T), _(TM,T), _(SM,T), _(SM,T), _(SM,T), _(x,x), _(x,x), _(SM,B),
+ /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A88 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A98 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x1b00u 2120
++#define indic_offset_0x1b00u 2152
+
+
+ /* Balinese */
+
+- /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 1B00 */ _(Bi,T), _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,T), _(M,T),
++ /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,T), _(M,R), _(M,T), _(M,T),
+ /* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L),
+ /* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x),
+ /* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1B58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,T), _(x,B), _(x,T), _(x,T), _(x,T),
++ /* 1B70 */ _(x,T), _(x,T), _(x,T), _(x,T), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sundanese */
+
+- /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 1B80 */ _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R),
+- /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
++ /* 1BA0 */ _(C,x), _(CS,R), _(CS,B), _(CS,B), _(M,T), _(M,B), _(M,L), _(M,R),
++ /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,B), _(CS,B), _(C,x), _(C,x),
+ /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1BB8 */ _(Nd,x), _(Nd,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
+
+ /* Batak */
+
+ /* 1BC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,R),
++ /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,T), _(M,R),
+ /* 1BE8 */ _(M,T), _(M,T), _(M,R), _(M,R), _(M,R), _(M,T), _(M,R), _(M,T),
+- /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 1BF0 */ _(CF,T), _(CF,T), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Lepcha */
+
+ /* 1C00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1C10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L),
+- /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x),
+- /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L), _(x,x), _(N,x),
++ /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,R), _(CS,R), _(M,R), _(M,L),
++ /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,T), _(CF,T), _(CF,T),
++ /* 1C30 */ _(CF,T), _(CF,T), _(CF,T), _(CF,T), _(Bi,L), _(Bi,L), _(SM,T), _(N,B),
+ /* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1C48 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
+
+-#define indic_offset_0x1cd0u 2456
++#define indic_offset_0x1cd0u 2488
+
+
+ /* Vedic Extensions */
+
+- /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x), _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+- /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+- /* 1CE0 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(TM,x), _(x,x), _(x,x), _(x,x),
++ /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
++ /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
++ /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O),
++ /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x),
++ /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(Ca,T), _(x,x), _(x,x), _(x,x),
++ /* 1CF8 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x2008u 2496
++#define indic_offset_0x2008u 2536
+
+
+ /* General Punctuation */
+
+ /* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
+- /* 2010 */ _(x,x), _(x,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
++ /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0xa800u 2512
++#define indic_offset_0x2070u 2552
++
++
++ /* Superscripts and Subscripts */
++
++ /* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x),
++ /* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x),
++
++#define indic_offset_0xa800u 2576
+
+
+ /* Syloti Nagri */
+
+ /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T), _(C,x),
+- /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,T), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R),
+ /* A828 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A830 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A838 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Phags-pa */
+@@ -520,158 +538,158 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* A858 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x),
+ /* A860 */ _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(CS,x),
+ /* A868 */ _(CS,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A870 */ _(C,x), _(CS,x), _(C,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A878 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Saurashtra */
+
+- /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* A880 */ _(Bi,R), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A890 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A898 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A8A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A8A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(M,R), _(M,R), _(M,R),
++ /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,R), _(M,R), _(M,R), _(M,R),
+ /* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
+ /* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x),
+ /* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A8D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Devanagari Extended */
+
+- /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+- /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+- /* A8F0 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
++ /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
++ /* A8F0 */ _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Kayah Li */
+
+ /* A900 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A908 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
+- /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x),
++ /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,B), _(TM,B), _(TM,B), _(x,x), _(x,x),
+
+ /* Rejang */
+
+ /* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B),
+- /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x),
+- /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,T),
++ /* A950 */ _(CF,T), _(CF,T), _(CF,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A970 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Javanese */
+
+- /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* A980 */ _(Bi,T), _(Bi,T),_(CSR,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,R), _(M,T), _(M,T),
+- /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x),
++ /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,T), _(M,R), _(M,R), _(M,T), _(M,T),
++ /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,R), _(CM,R), _(CM,R),
+ /* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A9D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Myanmar Extended-B */
+
+- /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(C,x),
++ /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x),
+ /* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
+
+ /* Cham */
+
+ /* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
+ /* AA08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L),
+- /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x), _(x,x),
++ /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,R), _(CM,L), _(CM,B), _(CM,B), _(x,x),
+ /* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+- /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x),
++ /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
++ /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,T), _(CF,R), _(x,x), _(x,x),
+ /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* AA58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Myanmar Extended-A */
+
+ /* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
++ /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
+
+ /* Tai Viet */
+
+ /* AA80 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA88 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AA98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAB0 */ _(M,T), _(M,R), _(M,T), _(M,T), _(M,B),_(M,VOL),_(M,VOL), _(M,T),
+- /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,x),
+- /* AAC0 */ _(TL,x), _(TM,x), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,T),
++ /* AAC0 */ _(TL,x), _(TM,T), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Meetei Mayek Extensions */
+
+ /* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R),
+- /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(IS,x), _(x,x),
++ /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,R), _(IS,x), _(x,x),
+
+-#define indic_offset_0xabc0u 3272
++#define indic_offset_0xabc0u 3336
+
+
+ /* Meetei Mayek */
+
+ /* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x),
+ /* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
+ /* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R),
+- /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(PK,B), _(x,x), _(x,x),
++ /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,R), _(PK,B), _(x,x), _(x,x),
+ /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* ABF8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x10a00u 3336
++#define indic_offset_0x10a00u 3400
+
+
+ /* Kharoshthi */
+
+ /* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x),
+- /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x),
++ /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(M,B), _(Bi,B), _(Vs,T),
+ /* 10A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 10A18 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
++ /* 10A38 */ _(N,T), _(N,B), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
+ /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+
+-#define indic_offset_0x11000u 3408
++#define indic_offset_0x11000u 3472
+
+
+ /* Brahmi */
+
+- /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11000 */ _(Bi,R), _(Bi,T), _(Vs,R),_(CWS,x),_(CWS,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11010 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11020 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11028 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11030 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11038 */ _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B),
+ /* 11040 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x),
+@@ -680,62 +698,62 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* 11058 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
+ /* 11060 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x), _(Nd,x), _(Nd,x),
+ /* 11068 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 11070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(NJ,x),
+
+ /* Kaithi */
+
+- /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11080 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 11090 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11098 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R),
+- /* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 110B8 */ _(M,R), _(V,B), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11100u 3600
++#define indic_offset_0x11100u 3664
+
+
+ /* Chakma */
+
+- /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
++ /* 11100 */ _(Bi,T), _(Bi,T), _(Vs,T), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11110 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11120 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
+ /* 11128 */ _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T), _(M,TB), _(M,TB),
+ /* 11130 */ _(M,T), _(M,B), _(M,B), _(IS,x), _(PK,T), _(x,x), _(Nd,x), _(Nd,x),
+ /* 11138 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 11140 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11148 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Mahajani */
+
+ /* 11150 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x),
+ /* 11158 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11160 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11168 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,B), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11178 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sharada */
+
+- /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11180 */ _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11190 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11198 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 111A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 111A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 111B0 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,L), _(M,R), _(M,B), _(M,B),
+ /* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR),
+- /* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 111C0 */ _(V,R), _(A,x),_(CPrf,x),_(CPrf,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 111C8 */ _(x,x), _(x,x), _(N,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x),
+ /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sinhala Archaic Numbers */
+
+ /* 111E0 */ _(x,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x),
+@@ -744,163 +762,193 @@ static const INDIC_TABLE_ELEMENT_TYPE in
+ /* Khojki */
+
+ /* 11200 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11208 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11210 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11218 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11220 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11228 */ _(C,x), _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,R), _(M,B),
+- /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,x), _(V,R), _(N,x), _(GM,T),
++ /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,T), _(V,R), _(N,T), _(GM,T),
+
+-#define indic_offset_0x112b0u 3912
++#define indic_offset_0x11280u 3976
+
+
++ /* Multani */
++
++ /* 11280 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(x,x),
++ /* 11288 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x),
++ /* 11290 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11298 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x),
++ /* 112A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 112A8 */ _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++
+ /* Khudawadi */
+
+ /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 112B8 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112C0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112C8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112D0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,x),
++ /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,T),
+ /* 112E0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
+- /* 112E8 */ _(M,T), _(N,x), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 112E8 */ _(M,T), _(N,B), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 112F8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Grantha */
+
+- /* 11300 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
++ /* 11300 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 11310 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 11318 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11320 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11328 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11330 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 11338 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,R),
+ /* 11340 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(x,x), _(M,L),
+ /* 11348 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,R), _(x,x), _(x,x),
+ /* 11350 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 11358 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+- /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,x), _(Ca,x),
+- /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
+- /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
++ /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,T), _(Ca,T),
++ /* 11368 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x),
++ /* 11370 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11480u 4112
++#define indic_offset_0x11480u 4224
+
+
+ /* Tirhuta */
+
+ /* 11480 */ _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11488 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* 11490 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11498 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+- /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,x),
+- /* 114C0 */ _(Bi,x), _(Vs,x), _(V,B), _(N,x), _(A,x), _(x,x), _(x,x), _(x,x),
++ /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,T),
++ /* 114C0 */ _(Bi,T), _(Vs,R), _(V,B), _(N,B), _(A,x), _(x,x), _(x,x), _(x,x),
+ /* 114C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 114D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-#define indic_offset_0x11580u 4208
++#define indic_offset_0x11580u 4320
+
+
+ /* Siddham */
+
+ /* 11580 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11588 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
+ /* 11590 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11598 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 115A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 115A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,R),
+ /* 115B0 */ _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x),
+- /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x), _(V,B),
+- /* 115C0 */ _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+-
+-#define indic_offset_0x11600u 4280
+-
++ /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,T), _(Bi,T), _(Vs,R), _(V,B),
++ /* 115C0 */ _(N,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115D8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x),
++ /* 115E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 115F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Modi */
+
+ /* 11600 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11608 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
+ /* 11610 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11618 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11620 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11628 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11630 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+- /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,x), _(Vs,x), _(V,B),
+- /* 11640 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,T), _(Vs,R), _(V,B),
++ /* 11640 */ _(M,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11648 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 11658 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11660 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11668 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11670 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11678 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Takri */
+
+ /* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11688 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11690 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11698 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 116A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+- /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R),
+- /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x),
++ /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,T), _(Vs,R), _(M,T), _(M,L), _(M,R),
++ /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,R), _(N,B),
+ /* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 116C8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 116F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+-}; /* Table items: 4488; occupancy: 73% */
++ /* Ahom */
++
++ /* 11700 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11710 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
++ /* 11718 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(CM,B), _(CM,x), _(CM,T),
++ /* 11720 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T),
++ /* 11728 */ _(M,B), _(M,T), _(M,T), _(PK,T), _(x,x), _(x,x), _(x,x), _(x,x),
++ /* 11730 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
++ /* 11738 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x),
++
++}; /* Table items: 4768; occupancy: 72% */
+
+ INDIC_TABLE_ELEMENT_TYPE
+ hb_indic_get_categories (hb_codepoint_t u)
+ {
+ switch (u >> 12)
+ {
+ case 0x0u:
+ if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+- if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
++ if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
+ if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+ if (unlikely (u == 0x00A0u)) return _(CP,x);
+ break;
+
+ case 0x1u:
+ if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+ if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
+ if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
+ if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
+- if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
++ if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+ break;
+
+ case 0x2u:
+ if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
++ if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
+ if (unlikely (u == 0x25CCu)) return _(CP,x);
+ break;
+
+ case 0xAu:
+ if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
+ if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
+ break;
+
+ case 0x10u:
+ if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
+ break;
+
+ case 0x11u:
+ if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
+ if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
+- if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
++ if (hb_in_range (u, 0x11280u, 0x11377u)) return indic_table[u - 0x11280u + indic_offset_0x11280u];
+ if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
+- if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+- if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
++ if (hb_in_range (u, 0x11580u, 0x1173Fu)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+ break;
+
+ default:
+ break;
+ }
+ return _(x,x);
+ }
+
+@@ -909,32 +957,36 @@ hb_indic_get_categories (hb_codepoint_t
+ #undef ISC_A
+ #undef ISC_Bi
+ #undef ISC_BJN
+ #undef ISC_Ca
+ #undef ISC_C
+ #undef ISC_CD
+ #undef ISC_CF
+ #undef ISC_CHL
++#undef ISC_CK
+ #undef ISC_CM
+ #undef ISC_CP
+ #undef ISC_CPR
++#undef ISC_CPrf
+ #undef ISC_CS
+ #undef ISC_CSR
++#undef ISC_CWS
+ #undef ISC_GM
+ #undef ISC_IS
+ #undef ISC_ZWJ
+ #undef ISC_ML
+ #undef ISC_ZWNJ
+ #undef ISC_N
+ #undef ISC_Nd
+ #undef ISC_NJ
+ #undef ISC_x
+ #undef ISC_PK
+ #undef ISC_RS
++#undef ISC_SM
+ #undef ISC_TL
+ #undef ISC_TM
+ #undef ISC_V
+ #undef ISC_Vs
+ #undef ISC_Vo
+ #undef ISC_M
+ #undef ISC_VI
+
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc
+@@ -171,34 +171,18 @@ set_indic_properties (hb_glyph_info_t &i
+ indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_position_t pos = (indic_position_t) (type >> 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,
+ 0x1CF5u, 0x1CF6u)))
+ cat = OT_C;
+ /* TODO: The following should only be allowed after a Visarga.
+ * For now, just treat them like regular tone marks. */
+ else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
+@@ -211,25 +195,22 @@ set_indic_properties (hb_glyph_info_t &i
+ /* The following take marks in standalone clusters, similar to Avagraha. */
+ else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
+ 0x1CE9u, 0x1CECu,
+ 0x1CEEu, 0x1CF1u)))
+ {
+ 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;
+ else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
+ else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
+ else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
+
+
+@@ -552,18 +533,25 @@ data_create_indic (const hb_ot_shape_pla
+ indic_plan->config = &indic_configs[i];
+ break;
+ }
+
+ indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+ 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);
+ indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+
+ for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
+ indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
+ 0 : plan->map.get_1_mask (indic_features[i].tag);
+@@ -1343,16 +1331,35 @@ final_reordering_syllable (const hb_ot_s
+ base++;
+ info[base].indic_position() = POS_BASE_C;
+
+ try_pref = false;
+ }
+ 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--;
+ break;
+ }
+ if (base == end && start < base &&
+ is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+ base--;
+@@ -1801,33 +1808,33 @@ decompose_indic (const hb_ot_shape_norma
+ {
+ /* Ok, safe to use Uniscribe-style decomposition. */
+ *a = 0x0DD9u;
+ *b = ab;
+ return true;
+ }
+ }
+
+- return c->unicode->decompose (ab, a, b);
++ return (bool) c->unicode->decompose (ab, a, b);
+ }
+
+ static bool
+ compose_indic (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+ {
+ /* Avoid recomposing split matras. */
+ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+ return false;
+
+ /* 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);
+ }
+
+
+ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+ {
+ "indic",
+ collect_features_indic,
+ override_features_indic,
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc
+@@ -194,16 +194,20 @@ set_myanmar_properties (hb_glyph_info_t
+ case 0x1004u: case 0x101Bu: case 0x105Au:
+ cat = (indic_category_t) OT_Ra;
+ break;
+
+ case 0x1032u: case 0x1036u:
+ cat = (indic_category_t) OT_A;
+ break;
+
++ case 0x1039u:
++ cat = (indic_category_t) OT_H;
++ break;
++
+ case 0x103Au:
+ cat = (indic_category_t) OT_As;
+ break;
+
+ case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
+ case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
+ case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
+ case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh
+@@ -39,19 +39,17 @@
+ #define complex_var_u8_1() var2.u8[3]
+
+
+ enum hb_ot_shape_zero_width_marks_type_t {
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ // HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+-
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
+ };
+
+
+ /* Master OT shaper list */
+ #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
+ HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
+ HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-thai.cc
+@@ -372,11 +372,11 @@ const hb_ot_complex_shaper_t _hb_ot_comp
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ preprocess_text_thai,
+ NULL, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
++ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ false,/* fallback_position */
+ };
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-tibetan.cc
+@@ -52,11 +52,11 @@ const hb_ot_complex_shaper_t _hb_ot_comp
+ 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 --git a/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-complex-use.cc
+@@ -280,16 +280,19 @@ setup_rphf_mask (const hb_ot_shape_plan_
+ info[i].mask |= mask;
+ }
+ }
+
+ static void
+ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer)
+ {
++ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
++ if (use_plan->arabic_plan)
++ return;
+
+ ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
+ hb_mask_t masks[4], all_masks = 0;
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ masks[i] = plan->map.get_1_mask (arabic_features[i]);
+ if (masks[i] == plan->map.get_global_mask ())
+ masks[i] = 0;
+@@ -355,17 +358,17 @@ setup_syllables (const hb_ot_shape_plan_
+ static void
+ clear_substitution_flags (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+ {
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+- _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (&info[i]);
++ _hb_glyph_info_clear_substituted (&info[i]);
+ }
+
+ static void
+ record_rphf (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+ {
+ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+@@ -400,66 +403,71 @@ record_pref (const hb_ot_shape_plan_t *p
+ if (_hb_glyph_info_substituted (&info[i]))
+ {
+ info[i].use_category() = USE_VPre;
+ break;
+ }
+ }
+ }
+
++static inline bool
++is_halant (const hb_glyph_info_t &info)
++{
++ return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
++}
++
+ static void
+ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
+ {
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+ /* Only a few syllable types need reordering. */
+ if (unlikely (!(FLAG_SAFE (syllable_type) &
+ (FLAG (virama_terminated_cluster) |
+ FLAG (consonant_cluster) |
+ FLAG (vowel_cluster) |
+ FLAG (broken_cluster) |
+ 0))))
+ return;
+
+ hb_glyph_info_t *info = buffer->info;
+
+-#define HALANT_FLAGS FLAG(USE_H)
+ #define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB) | FLAG (USE_IV))
+
+ /* Move things forward. */
+ if (info[start].use_category() == USE_R && end - start > 1)
+ {
+ /* Got a repha. Reorder it to after first base, before first halant. */
+ for (unsigned int i = start + 1; i < end; i++)
+- if (FLAG_UNSAFE (info[i].use_category()) & (HALANT_FLAGS | BASE_FLAGS))
++ if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i]))
+ {
+ /* If we hit a halant, move before it; otherwise it's a base: move to it's
+ * place, and shift things in between backward. */
+
+- if (info[i].use_category() == USE_H)
++ if (is_halant (info[i]))
+ i--;
+
+ buffer->merge_clusters (start, i + 1);
+ hb_glyph_info_t t = info[start];
+ memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
+ info[i] = t;
+
+ break;
+ }
+ }
+
+ /* Move things back. */
+ unsigned int j = end;
+ for (unsigned int i = start; i < end; i++)
+ {
+ uint32_t flag = FLAG_UNSAFE (info[i].use_category());
+- if (flag & (HALANT_FLAGS | BASE_FLAGS))
++ if ((flag & (BASE_FLAGS)) || is_halant (info[i]))
+ {
+- /* If we hit a halant, move before it; otherwise it's a base: move to it's
++ /* If we hit a halant, move after it; otherwise it's a base: move to it's
+ * place, and shift things in between backward. */
+- if (info[i].use_category() == USE_H)
++ if (is_halant (info[i]))
+ j = i + 1;
+ else
+ j = i;
+ }
+ else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
+ /* Only move the first component of a MultipleSubst. */
+ 0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
+ j < i)
+@@ -553,17 +561,17 @@ compose_use (const hb_ot_shape_normalize
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+ {
+ /* Avoid recomposing split matras. */
+ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+ return false;
+
+- return c->unicode->compose (a, b, ab);
++ return (bool)c->unicode->compose (a, b, ab);
+ }
+
+
+ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
+ {
+ "use",
+ collect_features_use,
+ NULL, /* override_features */
+diff --git a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc
+@@ -71,26 +71,26 @@
+ */
+
+ static bool
+ decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
+ {
+- return c->unicode->decompose (ab, a, b);
++ return (bool) c->unicode->decompose (ab, a, b);
+ }
+
+ static bool
+ compose_unicode (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+ {
+- return c->unicode->compose (a, b, ab);
++ return (bool) c->unicode->compose (a, b, ab);
+ }
+
+ static inline void
+ set_glyph (hb_glyph_info_t &info, hb_font_t *font)
+ {
+ font->get_glyph (info.codepoint, 0, &info.glyph_index());
+ }
+
+@@ -122,17 +122,17 @@ decompose (const hb_ot_shape_normalize_c
+ hb_codepoint_t a, b, a_glyph, b_glyph;
+ hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
+
+ if (!c->decompose (c, ab, &a, &b) ||
+ (b && !font->get_glyph (b, 0, &b_glyph)))
+ return 0;
+
+- bool has_a = font->get_glyph (a, 0, &a_glyph);
++ bool has_a = (bool) font->get_glyph (a, 0, &a_glyph);
+ if (shortest && has_a) {
+ /* Output a and b */
+ output_char (buffer, a, a_glyph);
+ if (likely (b)) {
+ output_char (buffer, b, b_glyph);
+ return 2;
+ }
+ return 1;
+diff --git a/gfx/harfbuzz/src/hb-ot-shape.cc b/gfx/harfbuzz/src/hb-ot-shape.cc
+--- a/gfx/harfbuzz/src/hb-ot-shape.cc
++++ b/gfx/harfbuzz/src/hb-ot-shape.cc
+@@ -657,42 +657,43 @@ hb_ot_position_default (hb_ot_shape_cont
+ unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+
+ 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);
+- if (c->font->has_glyph_v_origin_func ())
+- for (unsigned int i = 0; i < count; i++)
+- c->font->subtract_glyph_v_origin (info[i].codepoint,
+- &pos[i].x_offset,
+- &pos[i].y_offset);
++ 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
+ hb_ot_position_complex (hb_ot_shape_context_t *c)
+ {
+ 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
+ * is positioned hanging over the previous glyph. When
+ * direction is backward we don't shift and it will end up
+ * hanging over the next glyph after the final reordering.
+ * If fallback positinoing happens or GPOS is present, we don't
+ * care.
+@@ -721,24 +722,26 @@ hb_ot_position_complex (hb_ot_shape_cont
+
+ if (has_positioning)
+ {
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+
+ /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
+
++ /* 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);
+
++ /* 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;
+ }
+@@ -847,16 +850,18 @@ hb_bool_t
+ hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
+ hb_ot_shape_internal (&c);
+
+ return true;
+ }
+
+
+ /**
++ * 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,
+ hb_set_t *lookup_indexes /* OUT */)
+ {
+ /* XXX Does the first part always succeed? */
+@@ -880,16 +885,18 @@ add_char (hb_font_t *font,
+ hb_codepoint_t m = unicode->mirroring (u);
+ if (m != u && font->get_glyph (m, 0, &glyph))
+ glyphs->add (glyph);
+ }
+ }
+
+
+ /**
++ * hb_ot_shape_glyphs_closure:
++ *
+ * Since: 0.9.2
+ **/
+ void
+ hb_ot_shape_glyphs_closure (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ hb_set_t *glyphs)
+diff --git a/gfx/harfbuzz/src/hb-ot-shape.h b/gfx/harfbuzz/src/hb-ot-shape.h
+--- a/gfx/harfbuzz/src/hb-ot-shape.h
++++ b/gfx/harfbuzz/src/hb-ot-shape.h
+@@ -31,23 +31,23 @@
+ #ifndef HB_OT_SHAPE_H
+ #define HB_OT_SHAPE_H
+
+ #include "hb.h"
+
+ HB_BEGIN_DECLS
+
+ /* TODO port to shape-plan / set. */
+-void
++HB_EXTERN void
+ hb_ot_shape_glyphs_closure (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ hb_set_t *glyphs);
+
+-void
++HB_EXTERN void
+ hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+ hb_tag_t table_tag,
+ hb_set_t *lookup_indexes /* OUT */);
+
+ HB_END_DECLS
+
+ #endif /* HB_OT_SHAPE_H */
+diff --git a/gfx/harfbuzz/src/hb-ot-tag.cc b/gfx/harfbuzz/src/hb-ot-tag.cc
+--- a/gfx/harfbuzz/src/hb-ot-tag.cc
++++ b/gfx/harfbuzz/src/hb-ot-tag.cc
+@@ -350,17 +350,16 @@ static const LangTag ot_languages[] = {
+ {"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */
+ {"gv", HB_TAG('M','N','X',' ')}, /* Manx */
+ {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
+ {"har", HB_TAG('H','R','I',' ')}, /* Harari */
+ {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */
+ {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
+ {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
+ {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
+- {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
+ {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
+ {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
+ {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
+ {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
+ {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */
+ {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */
+ {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */
+ {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */
+@@ -596,18 +595,18 @@ static const LangTag ot_languages[] = {
+ {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
+ {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */
+ {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
+ {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */
+ {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
+ {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
+ {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
+ {"sat", HB_TAG('S','A','T',' ')}, /* Santali */
++ {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
+ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
+- {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
+ {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
+ {"sco", HB_TAG('S','C','O',' ')}, /* Scots */
+ {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */
+ {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */
+ {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
+ {"seh", HB_TAG('S','N','A',' ')}, /* Sena */
+ {"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
+ {"sg", HB_TAG('S','G','O',' ')}, /* Sango */
+@@ -685,29 +684,29 @@ static const LangTag ot_languages[] = {
+ {"umb", HB_TAG('U','M','B',' ')}, /* Umbundu */
+ {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */
+ {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */
+ {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */
+ {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek */
+ {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */
+ {"ve", HB_TAG('V','E','N',' ')}, /* Venda */
+ {"vec", HB_TAG('V','E','C',' ')}, /* Venetian */
++ {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
+ {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
+- {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
+ {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
+ {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
+ {"vro", HB_TAG('V','R','O',' ')}, /* Võro */
+ {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */
+ {"war", HB_TAG('W','A','R',' ')}, /* Waray (Philippines) */
+ {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
+ {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
+ {"wle", HB_TAG('S','I','G',' ')}, /* Wolane */
++ {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
+ {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
+ {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
+- {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
+ {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
+ {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
+ {"xog", HB_TAG('X','O','G',' ')}, /* Soga */
+ {"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
+ {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
+ {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */
+ {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */
+ {"yao", HB_TAG('Y','A','O',' ')}, /* Yao */
+@@ -923,9 +922,32 @@ hb_ot_tag_to_language (hb_tag_t tag)
+ buf[9] = tag & 0xFF;
+ if (buf[9] == 0x20)
+ buf[9] = '\0';
+ buf[10] = '\0';
+ return hb_language_from_string ((char *) buf, -1);
+ }
+ }
+
++static inline void
++test_langs_sorted (void)
++{
++ for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
++ {
++ int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
++ if (c >= 0)
++ {
++ fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
++ i, ot_languages[i-1].language, c, ot_languages[i].language);
++ abort();
++ }
++ }
++}
+
++#ifdef MAIN
++int
++main (void)
++{
++ test_langs_sorted ();
++ return 0;
++}
++
++#endif
+diff --git a/gfx/harfbuzz/src/hb-ot-tag.h b/gfx/harfbuzz/src/hb-ot-tag.h
+--- a/gfx/harfbuzz/src/hb-ot-tag.h
++++ b/gfx/harfbuzz/src/hb-ot-tag.h
+@@ -34,26 +34,26 @@
+ #include "hb.h"
+
+ HB_BEGIN_DECLS
+
+
+ #define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
+ #define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
+
+-void
++HB_EXTERN void
+ hb_ot_tags_from_script (hb_script_t script,
+ hb_tag_t *script_tag_1,
+ hb_tag_t *script_tag_2);
+
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_ot_tag_to_script (hb_tag_t tag);
+
+-hb_tag_t
++HB_EXTERN hb_tag_t
+ hb_ot_tag_from_language (hb_language_t language);
+
+-hb_language_t
++HB_EXTERN hb_language_t
+ hb_ot_tag_to_language (hb_tag_t tag);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_OT_TAG_H */
+diff --git a/gfx/harfbuzz/src/hb-private.hh b/gfx/harfbuzz/src/hb-private.hh
+--- a/gfx/harfbuzz/src/hb-private.hh
++++ b/gfx/harfbuzz/src/hb-private.hh
+@@ -48,19 +48,16 @@
+ /* We only use these two for debug output. However, the debug code is
+ * always seen by the compiler (and optimized out in non-debug builds.
+ * If including these becomes a problem, we can start thinking about
+ * someway around that. */
+ #include <stdio.h>
+ #include <errno.h>
+ #include <stdarg.h>
+
+-#ifdef _MSC_VER
+-#include <windows.h> /* ensure DEFINE_ENUM_FLAG_OPERATORS is defined */
+-#endif
+
+ /* Compile-time custom allocator support. */
+
+ #if defined(hb_malloc_impl) \
+ && defined(hb_calloc_impl) \
+ && defined(hb_realloc_impl) \
+ && defined(hb_free_impl)
+ extern "C" void* hb_malloc_impl(size_t size);
+@@ -177,16 +174,19 @@ extern "C" void hb_free_impl(void *ptr)
+ # define setlocale(Category, Locale) "C"
+ static int errno = 0; /* Use something better? */
+ # endif
+ # elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+ # define getenv(Name) NULL
+ # endif
+ # if defined(_MSC_VER) && _MSC_VER < 1900
+ # define snprintf _snprintf
++# elif defined(_MSC_VER) && _MSC_VER >= 1900
++# /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
++# define strdup _strdup
+ # endif
+ #endif
+
+ #if HAVE_ATEXIT
+ /* atexit() is only safe to be called from shared libraries on certain
+ * platforms. Whitelist.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
+ # if defined(__linux) && defined(__GLIBC_PREREQ)
+@@ -894,37 +894,32 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2,
+ }
+
+
+ /* Enable bitwise ops on enums marked as flags_t */
+ /* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another... So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+- * On MSVC use DEFINE_ENUM_FLAG_OPERATORS. See:
+- * https://github.com/behdad/harfbuzz/pull/163
++ * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
+ */
+ #ifdef _MSC_VER
+ # pragma warning(disable:4200)
+ # pragma warning(disable:4800)
+-# define HB_MARK_AS_FLAG_T(flags_t) DEFINE_ENUM_FLAG_OPERATORS (##flags_t##);
+-#else
+-# define HB_MARK_AS_FLAG_T(flags_t) template <> class hb_mark_as_flags_t<flags_t> {};
+-template <class T> class hb_mark_as_flags_t;
+-template <class T> static inline T operator | (T l, T r)
+-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l | (unsigned int) r); }
+-template <class T> static inline T operator & (T l, T r)
+-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T ((unsigned int) l & (unsigned int) r); }
+-template <class T> static inline T operator ~ (T r)
+-{ hb_mark_as_flags_t<T> unused HB_UNUSED; return T (~(unsigned int) r); }
+-template <class T> static inline T& operator |= (T &l, T r)
+-{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l | r; return l; }
+-template <class T> static inline T& operator &= (T& l, T r)
+-{ hb_mark_as_flags_t<T> unused HB_UNUSED; l = l & r; return l; }
+ #endif
++#define HB_MARK_AS_FLAG_T(T) \
++ extern "C++" { \
++ static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
++ static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
++ static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
++ static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
++ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
++ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
++ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
++ }
+
+
+ /* Useful for set-operations on small enums.
+ * For example, for testing "x ∈ {x1, x2, x3}" use:
+ * (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
+ */
+ #define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((x) < 32) + (1U << (x)))
+ #define FLAG_SAFE(x) (1U << (x))
+@@ -1005,10 +1000,12 @@ static inline hb_options_t
+ hb_options (void)
+ {
+ if (unlikely (!_hb_options.i))
+ _hb_options_init ();
+
+ return _hb_options.opts;
+ }
+
++/* Size signifying variable-sized array */
++#define VAR 1
+
+ #endif /* HB_PRIVATE_HH */
+diff --git a/gfx/harfbuzz/src/hb-set.h b/gfx/harfbuzz/src/hb-set.h
+--- a/gfx/harfbuzz/src/hb-set.h
++++ b/gfx/harfbuzz/src/hb-set.h
+@@ -39,119 +39,119 @@ HB_BEGIN_DECLS
+ /*
+ * Since: 0.9.21
+ */
+ #define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
+ typedef struct hb_set_t hb_set_t;
+
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_create (void);
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_get_empty (void);
+
+-hb_set_t *
++HB_EXTERN hb_set_t *
+ hb_set_reference (hb_set_t *set);
+
+-void
++HB_EXTERN void
+ hb_set_destroy (hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_set_user_data (hb_set_t *set,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+-void *
++HB_EXTERN void *
+ hb_set_get_user_data (hb_set_t *set,
+ hb_user_data_key_t *key);
+
+
+ /* Returns false if allocation has failed before */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_allocation_successful (const hb_set_t *set);
+
+-void
++HB_EXTERN void
+ hb_set_clear (hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_is_empty (const hb_set_t *set);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_has (const hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+ /* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1
+ * which we will use as a sentinel. */
+-void
++HB_EXTERN void
+ hb_set_add (hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+-void
++HB_EXTERN void
+ hb_set_add_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
+-void
++HB_EXTERN void
+ hb_set_del (hb_set_t *set,
+ hb_codepoint_t codepoint);
+
+-void
++HB_EXTERN void
+ hb_set_del_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_is_equal (const hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_set (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_union (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_intersect (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_subtract (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_symmetric_difference (hb_set_t *set,
+ const hb_set_t *other);
+
+-void
++HB_EXTERN void
+ hb_set_invert (hb_set_t *set);
+
+-unsigned int
++HB_EXTERN unsigned int
+ hb_set_get_population (const hb_set_t *set);
+
+ /* Returns -1 if set empty. */
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_set_get_min (const hb_set_t *set);
+
+ /* Returns -1 if set empty. */
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_set_get_max (const hb_set_t *set);
+
+ /* Pass -1 in to get started. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_next (const hb_set_t *set,
+ hb_codepoint_t *codepoint);
+
+ /* Pass -1 for first and last to get started. */
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_set_next_range (const hb_set_t *set,
+ hb_codepoint_t *first,
+ hb_codepoint_t *last);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_SET_H */
+diff --git a/gfx/harfbuzz/src/hb-shape-plan.h b/gfx/harfbuzz/src/hb-shape-plan.h
+--- a/gfx/harfbuzz/src/hb-shape-plan.h
++++ b/gfx/harfbuzz/src/hb-shape-plan.h
+@@ -33,57 +33,57 @@
+
+ #include "hb-common.h"
+ #include "hb-font.h"
+
+ HB_BEGIN_DECLS
+
+ typedef struct hb_shape_plan_t hb_shape_plan_t;
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_create (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_create_cached (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_get_empty (void);
+
+-hb_shape_plan_t *
++HB_EXTERN hb_shape_plan_t *
+ hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+-void
++HB_EXTERN void
+ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+-void *
++HB_EXTERN void *
+ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key);
+
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+-const char *
++HB_EXTERN const char *
+ hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_SHAPE_PLAN_H */
+diff --git a/gfx/harfbuzz/src/hb-shape.cc b/gfx/harfbuzz/src/hb-shape.cc
+--- a/gfx/harfbuzz/src/hb-shape.cc
++++ b/gfx/harfbuzz/src/hb-shape.cc
+@@ -205,23 +205,25 @@ parse_one_feature (const char **pp, cons
+ parse_feature_value_postfix (pp, end, feature) &&
+ parse_space (pp, end) &&
+ *pp == end;
+ }
+
+ /**
+ * hb_feature_from_string:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+- * @len: length of @str, or -1 if string is nul-terminated
++ * @len: length of @str, or -1 if string is %NULL terminated
+ * @feature: (out): the #hb_feature_t to initialize with the parsed values
+ *
+- * Parses a string into a #hb_feature_t. If @len is -1 then @str is
+- * %NULL-terminated.
++ * Parses a string into a #hb_feature_t.
+ *
+- * Return value: %TRUE if @str is successfully parsed, %FALSE otherwise
++ * TODO: document the syntax here.
++ *
++ * Return value:
++ * %true if @str is successfully parsed, %false otherwise.
+ *
+ * Since: 0.9.5
+ **/
+ hb_bool_t
+ hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature)
+ {
+ hb_feature_t feat;
+diff --git a/gfx/harfbuzz/src/hb-shape.h b/gfx/harfbuzz/src/hb-shape.h
+--- a/gfx/harfbuzz/src/hb-shape.h
++++ b/gfx/harfbuzz/src/hb-shape.h
+@@ -42,37 +42,37 @@ HB_BEGIN_DECLS
+
+ typedef struct hb_feature_t {
+ hb_tag_t tag;
+ uint32_t value;
+ unsigned int start;
+ unsigned int end;
+ } hb_feature_t;
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature);
+
+-void
++HB_EXTERN void
+ hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size);
+
+
+-void
++HB_EXTERN void
+ hb_shape (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_shape_full (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shaper_list);
+
+-const char **
++HB_EXTERN const char **
+ hb_shape_list_shapers (void);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_SHAPE_H */
+diff --git a/gfx/harfbuzz/src/hb-shaper-list.hh b/gfx/harfbuzz/src/hb-shaper-list.hh
+--- a/gfx/harfbuzz/src/hb-shaper-list.hh
++++ b/gfx/harfbuzz/src/hb-shaper-list.hh
+@@ -41,15 +41,18 @@ HB_SHAPER_IMPLEMENT (coretext_aat)
+
+ #ifdef HAVE_OT
+ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+ #endif
+
+ #ifdef HAVE_UNISCRIBE
+ HB_SHAPER_IMPLEMENT (uniscribe)
+ #endif
++#ifdef HAVE_DIRECTWRITE
++HB_SHAPER_IMPLEMENT (directwrite)
++#endif
+ #ifdef HAVE_CORETEXT
+ HB_SHAPER_IMPLEMENT (coretext)
+ #endif
+
+ #ifdef HAVE_FALLBACK
+ HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
+ #endif
+diff --git a/gfx/harfbuzz/src/hb-unicode.h b/gfx/harfbuzz/src/hb-unicode.h
+--- a/gfx/harfbuzz/src/hb-unicode.h
++++ b/gfx/harfbuzz/src/hb-unicode.h
+@@ -169,52 +169,52 @@ typedef enum
+ */
+
+ typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
+
+
+ /*
+ * just give me the best implementation you've got there.
+ */
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_default (void);
+
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_create (hb_unicode_funcs_t *parent);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_empty (void);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
+
+-void
++HB_EXTERN void
+ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+
+-void *
++HB_EXTERN void *
+ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key);
+
+
+-void
++HB_EXTERN void
+ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
+
+-hb_unicode_funcs_t *
++HB_EXTERN hb_unicode_funcs_t *
+ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
+
+
+ /*
+ * funcs
+ */
+
+ /* typedefs */
+@@ -280,191 +280,207 @@ typedef unsigned int (*hb_unicode_deco
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_combining_class_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_eastasian_width_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_general_category_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_general_category_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_mirroring_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_mirroring_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_script_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_script_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_compose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_compose_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_decompose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_decompose_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ **/
+-void
++HB_EXTERN void
+ hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_decompose_compatibility_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+ /* accessors */
+
+ /**
++ * hb_unicode_combining_class:
++ *
+ * Since: 0.9.2
+ **/
+-hb_unicode_combining_class_t
++HB_EXTERN hb_unicode_combining_class_t
+ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+ /**
++ * hb_unicode_eastasian_width:
++ *
+ * Since: 0.9.2
+ **/
+-unsigned int
++HB_EXTERN unsigned int
+ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+ /**
++ * hb_unicode_general_category:
++ *
+ * Since: 0.9.2
+ **/
+-hb_unicode_general_category_t
++HB_EXTERN hb_unicode_general_category_t
+ hb_unicode_general_category (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+ /**
++ * hb_unicode_mirroring:
++ *
+ * Since: 0.9.2
+ **/
+-hb_codepoint_t
++HB_EXTERN hb_codepoint_t
+ hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+ /**
++ * hb_unicode_script:
++ *
+ * Since: 0.9.2
+ **/
+-hb_script_t
++HB_EXTERN hb_script_t
+ hb_unicode_script (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+ /**
++ * hb_unicode_compose:
++ *
+ * Since: 0.9.2
+ **/
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab);
+
+ /**
++ * hb_unicode_decompose:
++ *
+ * Since: 0.9.2
+ **/
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b);
+
+ /**
++ * hb_unicode_decompose_compatibility:
++ *
+ * Since: 0.9.2
+ **/
+-unsigned int
++HB_EXTERN unsigned int
+ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed);
+
+ HB_END_DECLS
+
+ #endif /* HB_UNICODE_H */
+diff --git a/gfx/harfbuzz/src/hb-uniscribe.cc b/gfx/harfbuzz/src/hb-uniscribe.cc
+--- a/gfx/harfbuzz/src/hb-uniscribe.cc
++++ b/gfx/harfbuzz/src/hb-uniscribe.cc
+@@ -914,17 +914,17 @@ retry:
+ log_clusters + chars_offset,
+ char_props + chars_offset,
+ glyphs + glyphs_offset,
+ glyph_props + glyphs_offset,
+ (int *) &glyphs_len);
+
+ if (unlikely (items[i].a.fNoGlyphIndex))
+ FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
+- if (unlikely (hr == E_OUTOFMEMORY))
++ if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER))
+ {
+ if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+ FAIL ("Buffer resize failed");
+ goto retry;
+ }
+ if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
+ {
+ if (items[i].a.eScript == SCRIPT_UNDEFINED)
+@@ -1014,17 +1014,17 @@ retry:
+ buffer->clear_positions ();
+ double x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+ for (unsigned int i = 0; i < glyphs_len; i++)
+ {
+ hb_glyph_info_t *info = &buffer->info[i];
+ hb_glyph_position_t *pos = &buffer->pos[i];
+
+ /* TODO vertical */
+- pos->x_advance = x_mult * info->mask;
++ pos->x_advance = x_mult * (int32_t) info->mask;
+ pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
+ pos->y_offset = y_mult * info->var2.i32;
+ }
+
+ if (backward)
+ hb_buffer_reverse (buffer);
+
+ /* Wow, done! */
+diff --git a/gfx/harfbuzz/src/hb-uniscribe.h b/gfx/harfbuzz/src/hb-uniscribe.h
+--- a/gfx/harfbuzz/src/hb-uniscribe.h
++++ b/gfx/harfbuzz/src/hb-uniscribe.h
+@@ -29,18 +29,18 @@
+
+ #include "hb.h"
+
+ #include <windows.h>
+
+ HB_BEGIN_DECLS
+
+
+-LOGFONTW *
++HB_EXTERN LOGFONTW *
+ hb_uniscribe_font_get_logfontw (hb_font_t *font);
+
+-HFONT
++HB_EXTERN HFONT
+ hb_uniscribe_font_get_hfont (hb_font_t *font);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_UNISCRIBE_H */
+diff --git a/gfx/harfbuzz/src/hb-version.h b/gfx/harfbuzz/src/hb-version.h
+--- a/gfx/harfbuzz/src/hb-version.h
++++ b/gfx/harfbuzz/src/hb-version.h
+@@ -33,34 +33,34 @@
+
+ #include "hb-common.h"
+
+ HB_BEGIN_DECLS
+
+
+ #define HB_VERSION_MAJOR 1
+ #define HB_VERSION_MINOR 1
+-#define HB_VERSION_MICRO 0
++#define HB_VERSION_MICRO 3
+
+-#define HB_VERSION_STRING "1.1.0"
++#define HB_VERSION_STRING "1.1.3"
+
+ #define HB_VERSION_ATLEAST(major,minor,micro) \
+ ((major)*10000+(minor)*100+(micro) <= \
+ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
+
+
+-void
++HB_EXTERN void
+ hb_version (unsigned int *major,
+ unsigned int *minor,
+ unsigned int *micro);
+
+-const char *
++HB_EXTERN const char *
+ hb_version_string (void);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_VERSION_H */
+diff --git a/gfx/harfbuzz/src/hb-version.h.in b/gfx/harfbuzz/src/hb-version.h.in
+--- a/gfx/harfbuzz/src/hb-version.h.in
++++ b/gfx/harfbuzz/src/hb-version.h.in
+@@ -42,25 +42,25 @@ HB_BEGIN_DECLS
+
+ #define HB_VERSION_STRING "@HB_VERSION@"
+
+ #define HB_VERSION_ATLEAST(major,minor,micro) \
+ ((major)*10000+(minor)*100+(micro) <= \
+ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
+
+
+-void
++HB_EXTERN void
+ hb_version (unsigned int *major,
+ unsigned int *minor,
+ unsigned int *micro);
+
+-const char *
++HB_EXTERN const char *
+ hb_version_string (void);
+
+-hb_bool_t
++HB_EXTERN hb_bool_t
+ hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
+
+
+ HB_END_DECLS
+
+ #endif /* HB_VERSION_H */
+diff --git a/gfx/harfbuzz/src/hb.h b/gfx/harfbuzz/src/hb.h
+--- a/gfx/harfbuzz/src/hb.h
++++ b/gfx/harfbuzz/src/hb.h
+@@ -23,16 +23,20 @@
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+ #ifndef HB_H
+ #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"
+ #include "hb-deprecated.h"
+ #include "hb-face.h"
+ #include "hb-font.h"
+ #include "hb-set.h"
+ #include "hb-shape.h"
+diff --git a/gfx/harfbuzz/src/sample.py b/gfx/harfbuzz/src/sample.py
+--- a/gfx/harfbuzz/src/sample.py
++++ b/gfx/harfbuzz/src/sample.py
+@@ -28,16 +28,22 @@ del blob
+ font = hb.font_create (face)
+ upem = hb.face_get_upem (face)
+ del face
+ hb.font_set_scale (font, upem, upem)
+ #hb.ft_font_set_funcs (font)
+ hb.ot_font_set_funcs (font)
+
+ buf = hb.buffer_create ()
++class Debugger(object):
++ def message (self, buf, font, msg, data, _x_what_is_this):
++ print(msg)
++ return True
++debugger = Debugger()
++hb.buffer_set_message_func (buf, debugger.message, 1, 0)
+ hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+ hb.buffer_guess_segment_properties (buf)
+
+ hb.shape (font, buf, [])
+ del font
+
+ infos = hb.buffer_get_glyph_infos (buf)
+ positions = hb.buffer_get_glyph_positions (buf)
+diff --git a/gfx/harfbuzz/src/test.cc b/gfx/harfbuzz/src/test.cc
+--- a/gfx/harfbuzz/src/test.cc
++++ b/gfx/harfbuzz/src/test.cc
+@@ -115,17 +115,17 @@ main (int argc, char **argv)
+ {
+ hb_glyph_info_t *info = &infos[i];
+ hb_glyph_position_t *pos = &positions[i];
+
+ printf ("cluster %d glyph 0x%x at (%d,%d)+(%d,%d)\n",
+ info->cluster,
+ info->codepoint,
+ pos->x_offset,
+- pos->x_offset,
++ pos->y_offset,
+ pos->x_advance,
+ pos->y_advance);
+
+ }
+
+ hb_buffer_destroy (buffer);
+ hb_font_destroy (font);
+ hb_face_destroy (face);
diff --git a/libre/icedove/vendor.js b/libre/icedove/vendor.js
index 4d58bfc4a..75018d34c 100644
--- a/libre/icedove/vendor.js
+++ b/libre/icedove/vendor.js
@@ -8,6 +8,9 @@ pref("mail.shell.checkDefaultMail", false);
pref("extensions.autoDisableScopes", 11);
pref("extensions.shownSelectionUI", true);
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1245783
+pref("javascript.options.ion", false);
+
// Disable Social API for content
pref("social.remote-install.enabled", false);
pref("social.toast-notifications.enabled", false);
@@ -20,4 +23,4 @@ pref("social.directories", "");
pref("geo.enabled", false);
// Pointing the "Help -> What's new" menu entry to mozilla.debian.net
-pref("mailnews.start_page.override_url", "http://wiki.debian.org/Icedove/WhatsNew38");
+pref("mailnews.start_page.override_url", "http://wiki.debian.org/Icedove/WhatsNew45");