From ac5c4d77d022829d1b5b8e0f32ba1cc60427c34b Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 23 Jun 2016 13:03:03 -0300 Subject: icecat-38.8.0_gnu1-3: add harfbuzz patch --- libre/icecat/PKGBUILD | 25 +- libre/icecat/harfbuzz-1.1.3.patch | 27038 ++++++++++++++++++++++++++++++++++++ 2 files changed, 27053 insertions(+), 10 deletions(-) create mode 100644 libre/icecat/harfbuzz-1.1.3.patch (limited to 'libre') diff --git a/libre/icecat/PKGBUILD b/libre/icecat/PKGBUILD index f0feee2d9..9a837aac4 100644 --- a/libre/icecat/PKGBUILD +++ b/libre/icecat/PKGBUILD @@ -15,12 +15,12 @@ _pgo=true pkgname=icecat _pkgver=38.8.0-gnu1 pkgver=${_pkgver//-/_} -pkgrel=2 +pkgrel=3 pkgdesc="GNU IceCat, the standalone web browser based on Mozilla Firefox." arch=(i686 x86_64) license=(MPL GPL LGPL) -depends=(alsa-lib dbus-glib gtk2 hicolor-icon-theme hunspell icu=57.1 libevent libvpx=1.5.0 libxt mime-types mozilla-common mozilla-searchplugins nss sqlite startup-notification ttf-font) +depends=(alsa-lib dbus-glib ffmpeg gtk2 hunspell icu=57.1 libevent libvpx=1.5.0 libxt mime-types mozilla-common mozilla-searchplugins nss sqlite startup-notification ttf-font) makedepends=(diffutils gst-plugins-base-libs imake inetutils libpulse mesa python2 unzip yasm zip) options=(!emptydirs !makeflags debug) if $_pgo; then @@ -28,8 +28,7 @@ if $_pgo; then options+=(!ccache) fi optdepends=('networkmanager: Location detection via available WiFi networks' - 'gst-plugins-good: h.264 video' - 'gst-libav: h.264 video') + 'upower: Battery API') url="http://www.gnu.org/software/gnuzilla/" install=$pkgname.install source=(http://ftp.gnu.org/gnu/gnuzilla/${_pkgver%-*}/$pkgname-$_pkgver.tar.bz2{,.sig} @@ -40,12 +39,11 @@ source=(http://ftp.gnu.org/gnu/gnuzilla/${_pkgver%-*}/$pkgname-$_pkgver.tar.bz2{ gnu_headshadow.png $pkgname.desktop $pkgname-install-dir.patch - firefox-gcc-6.0.patch gcc6-fix-compilation-for-IceCat.patch mozilla-1228540-1.patch + firefox-gcc-6.0.patch gcc6-fix-compilation-for-IceCat.patch harfbuzz-1.1.3.patch mozilla-1228540-1.patch vendor.js $pkgname-fixed-loading-icon.png remove-google-play-services-support.patch disable-crypto-hardening-settings.patch) -mksha256sums=('1f58676fc0bdf60dc37145b8c97f507f0acec9bc84582aeef703cf0ed9744ed3') sha256sums=('97f76e85cc6f98463f0e0b0e845826816032770f9b589db69ece6b1cff21936c' 'SKIP' '19783b0cca336bca7c262f597acc176ca640756e7567ca6587a46b860f12ef91' @@ -55,6 +53,7 @@ sha256sums=('97f76e85cc6f98463f0e0b0e845826816032770f9b589db69ece6b1cff21936c' '5bdab2de5520fb4d3dbc453d9f73d20e0e077bf652bc780fc17184ba6c718a47' '4d1e1ddabc9e975ed39f49e134559a29e01cd49439e358233f1ede43bf5a52bf' '329cf6753d29ae64a4336a8a76ee71f0d331a39132159401e4d11de65b708a07' + '8a17454d2be90e94694818a1d1a6bdb615eced4d3a7a75af42080c99ce942f2f' 'd1ccbaf0973615c57f7893355e5cd3a89efb4e91071d0ec376e429b50cf6ed19' '977aa49b940f1da049cefa2878a63ac6669a78e63e9d55bb11db7b8f8fb64c33' '68e3a5b47c6d175cc95b98b069a15205f027cab83af9e075818d38610feb6213' @@ -78,10 +77,13 @@ prepare() { # Install to /usr/lib/$pkgname patch -Np1 -i "$srcdir/$pkgname-install-dir.patch" - # GCC 6 - patch -Np1 -i ../firefox-gcc-6.0.patch - patch -Np1 -i ../gcc6-fix-compilation-for-IceCat.patch - patch -Np1 -i ../mozilla-1228540-1.patch + # Compilation fix (FS#49243 and FS#49363), internet and Icedove package + patch -Np1 -i $srcdir/gcc6-fix-compilation-for-IceCat.patch + patch -Np1 -i $srcdir/firefox-gcc-6.0.patch + + # Update to harfbuzz 1.1.3 (following Icedove in [libre]) + patch -Np0 -i $srcdir/harfbuzz-1.1.3.patch + patch -Np1 -i $srcdir/mozilla-1228540-1.patch # Patch and remove anything that's left patch -Np1 -i "$srcdir/libre.patch" @@ -121,6 +123,9 @@ build() { # _FORTIFY_SOURCE causes configure failures CPPFLAGS+=" -O2" + # Hardening + LDFLAGS+=" -Wl,-z,now" + # GCC 6 CFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse -fno-schedule-insns2" CXXFLAGS+=" -fno-delete-null-pointer-checks -fno-lifetime-dse -fno-schedule-insns2" diff --git a/libre/icecat/harfbuzz-1.1.3.patch b/libre/icecat/harfbuzz-1.1.3.patch new file mode 100644 index 000000000..98e25914d --- /dev/null +++ b/libre/icecat/harfbuzz-1.1.3.patch @@ -0,0 +1,27038 @@ +diff -uN gfx/harfbuzz/src_old/check-defs.sh gfx/harfbuzz/src/check-defs.sh +--- gfx/harfbuzz/src_old/check-defs.sh 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/check-defs.sh 2016-06-05 23:47:59.650463392 +0200 +@@ -0,0 +1,44 @@ ++#!/bin/sh ++ ++LC_ALL=C ++export LC_ALL ++ ++test -z "$srcdir" && srcdir=. ++test -z "$MAKE" && MAKE=make ++stat=0 ++ ++if which nm 2>/dev/null >/dev/null; then ++ : ++else ++ echo "check-defs.sh: 'nm' not found; skipping test" ++ exit 77 ++fi ++ ++defs="harfbuzz.def" ++$MAKE $defs > /dev/null ++tested=false ++for def in $defs; do ++ lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'` ++ so=.libs/lib${lib}.so ++ ++ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`" ++ ++ if test -f "$so"; then ++ ++ echo "Checking that $so has the same symbol list as $def" ++ { ++ echo EXPORTS ++ echo "$EXPORTED_SYMBOLS" ++ # cheat: copy the last line from the def file! ++ tail -n1 "$def" ++ } | diff "$def" - >&2 || stat=1 ++ ++ tested=true ++ fi ++done ++if ! $tested; then ++ echo "check-defs.sh: libharfbuzz shared library not found; skipping test" ++ exit 77 ++fi ++ ++exit $stat +diff -uN gfx/harfbuzz/src_old/check-header-guards.sh gfx/harfbuzz/src/check-header-guards.sh +--- gfx/harfbuzz/src_old/check-header-guards.sh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/check-header-guards.sh 2016-06-05 23:48:00.885456341 +0200 +@@ -9,13 +9,12 @@ + test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'` + test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'` + +- + for x in $HBHEADERS $HBSOURCES; do + test -f "$srcdir/$x" && x="$srcdir/$x" +- echo "$x" | grep '[^h]$' -q && continue; ++ echo "$x" | grep -q '[^h]$' && continue; + xx=`echo "$x" | sed 's@.*/@@'` + tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'` +- lines=`grep "\<$tag\>" "$x" | wc -l | sed 's/[ ]*//g'` ++ lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ ]*//g'` + if test "x$lines" != x3; then + echo "Ouch, header file $x does not have correct preprocessor guards" + stat=1 +diff -uN gfx/harfbuzz/src_old/check-libstdc++.sh gfx/harfbuzz/src/check-libstdc++.sh +--- gfx/harfbuzz/src_old/check-libstdc++.sh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/check-libstdc++.sh 2016-06-05 23:48:03.413441951 +0200 +@@ -19,9 +19,9 @@ + so=.libs/libharfbuzz.$suffix + if ! test -f "$so"; then continue; fi + +- echo "Checking that we are not linking to libstdc++" +- if ldd $so | grep 'libstdc[+][+]'; then +- echo "Ouch, linked to libstdc++" ++ echo "Checking that we are not linking to libstdc++ or libc++" ++ if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then ++ echo "Ouch, linked to libstdc++ or libc++" + stat=1 + fi + tested=true +diff -uN gfx/harfbuzz/src_old/gen-indic-table.py gfx/harfbuzz/src/gen-indic-table.py +--- gfx/harfbuzz/src_old/gen-indic-table.py 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/gen-indic-table.py 2016-06-05 23:48:08.239414549 +0200 +@@ -91,6 +91,7 @@ + "Visarga": 'Vs', + "Vowel": 'Vo', + "Vowel_Dependent": 'M', ++ "Consonant_Prefixed": 'CPrf', + "Other": 'x', + },{ + "Not_Applicable": 'x', +@@ -209,7 +210,7 @@ + for (start,end) in zip (starts, ends): + if p not in [start>>page_bits, end>>page_bits]: continue + offset = "indic_offset_0x%04xu" % start +- print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end, start, offset) ++ print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset) + for u,d in singles.items (): + if p != u>>page_bits: continue + print " if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]]) +diff -uN gfx/harfbuzz/src_old/gen-use-table.py gfx/harfbuzz/src/gen-use-table.py +--- gfx/harfbuzz/src_old/gen-use-table.py 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/gen-use-table.py 2016-06-05 23:48:09.467407592 +0200 +@@ -0,0 +1,476 @@ ++#!/usr/bin/python ++ ++import sys ++ ++if len (sys.argv) != 5: ++ print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt" ++ sys.exit (1) ++ ++BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"] ++ ++files = [file (x) for x in sys.argv[1:]] ++ ++headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 2] ++headers.append (["UnicodeData.txt does not have a header."]) ++ ++data = [{} for f in files] ++values = [{} for f in files] ++for i, f in enumerate (files): ++ for line in f: ++ ++ j = line.find ('#') ++ if j >= 0: ++ line = line[:j] ++ ++ fields = [x.strip () for x in line.split (';')] ++ if len (fields) == 1: ++ continue ++ ++ uu = fields[0].split ('..') ++ start = int (uu[0], 16) ++ if len (uu) == 1: ++ end = start ++ else: ++ end = int (uu[1], 16) ++ ++ t = fields[1 if i != 2 else 2] ++ ++ for u in range (start, end + 1): ++ data[i][u] = t ++ values[i][t] = values[i].get (t, 0) + end - start + 1 ++ ++defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block') ++ ++# TODO Characters that are not in Unicode Indic files, but used in USE ++data[0][0x034F] = defaults[0] ++data[0][0x2060] = defaults[0] ++for u in range (0xFE00, 0xFE0F + 1): ++ data[0][u] = defaults[0] ++ ++# Merge data into one dict: ++for i,v in enumerate (defaults): ++ values[i][v] = values[i].get (v, 0) + 1 ++combined = {} ++for i,d in enumerate (data): ++ for u,v in d.items (): ++ if i >= 2 and not u in combined: ++ continue ++ if not u in combined: ++ combined[u] = list (defaults) ++ combined[u][i] = v ++combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS} ++data = combined ++del combined ++num = len (data) ++ ++ ++property_names = [ ++ # General_Category ++ 'Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc', ++ 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', 'Pi', 'Po', ++ 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs', ++ # Indic_Syllabic_Category ++ 'Other', ++ 'Bindu', ++ 'Visarga', ++ 'Avagraha', ++ 'Nukta', ++ 'Virama', ++ 'Pure_Killer', ++ 'Invisible_Stacker', ++ 'Vowel_Independent', ++ 'Vowel_Dependent', ++ 'Vowel', ++ 'Consonant_Placeholder', ++ 'Consonant', ++ 'Consonant_Dead', ++ 'Consonant_With_Stacker', ++ 'Consonant_Prefixed', ++ 'Consonant_Preceding_Repha', ++ 'Consonant_Succeeding_Repha', ++ 'Consonant_Subjoined', ++ 'Consonant_Medial', ++ 'Consonant_Final', ++ 'Consonant_Head_Letter', ++ 'Modifying_Letter', ++ 'Tone_Letter', ++ 'Tone_Mark', ++ 'Gemination_Mark', ++ 'Cantillation_Mark', ++ 'Register_Shifter', ++ 'Syllable_Modifier', ++ 'Consonant_Killer', ++ 'Non_Joiner', ++ 'Joiner', ++ 'Number_Joiner', ++ 'Number', ++ 'Brahmi_Joining_Number', ++ # Indic_Positional_Category ++ 'Not_Applicable', ++ 'Right', ++ 'Left', ++ 'Visual_Order_Left', ++ 'Left_And_Right', ++ 'Top', ++ 'Bottom', ++ 'Top_And_Bottom', ++ 'Top_And_Right', ++ 'Top_And_Left', ++ 'Top_And_Left_And_Right', ++ 'Bottom_And_Right', ++ 'Top_And_Bottom_And_Right', ++ 'Overstruck', ++] ++ ++class PropertyValue(object): ++ def __init__(self, name_): ++ self.name = name_ ++ def __str__(self): ++ return self.name ++ def __eq__(self, other): ++ return self.name == (other if isinstance(other, basestring) else other.name) ++ def __ne__(self, other): ++ return not (self == other) ++ ++property_values = {} ++ ++for name in property_names: ++ value = PropertyValue(name) ++ assert value not in property_values ++ assert value not in globals() ++ property_values[name] = value ++globals().update(property_values) ++ ++ ++def is_BASE(U, UISC, UGC): ++ return (UISC in [Number, Consonant, Consonant_Head_Letter, ++ #SPEC-OUTDATED Consonant_Placeholder, ++ Tone_Letter] or ++ (UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial, ++ Consonant_Subjoined, Vowel, Vowel_Dependent])) ++def is_BASE_VOWEL(U, UISC, UGC): ++ return UISC == Vowel_Independent ++def is_BASE_IND(U, UISC, UGC): ++ #SPEC-BROKEN return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po) ++ return (UISC in [Consonant_Dead, Modifying_Letter] or ++ (UGC == Po and not is_BASE_OTHER(U, UISC, UGC))) # for 104E ++def is_BASE_NUM(U, UISC, UGC): ++ return UISC == Brahmi_Joining_Number ++def is_BASE_OTHER(U, UISC, UGC): ++ if UISC == Consonant_Placeholder: return True #SPEC-OUTDATED ++ return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC, ++ 0x25FB, 0x25FC, 0x25FD, 0x25FE] ++def is_CGJ(U, UISC, UGC): ++ return U == 0x034F ++def is_CONS_FINAL(U, UISC, UGC): ++ return ((UISC == Consonant_Final and UGC != Lo) or ++ UISC == Consonant_Succeeding_Repha) ++def is_CONS_FINAL_MOD(U, UISC, UGC): ++ #SPEC-OUTDATED return UISC in [Consonant_Final_Modifier, Syllable_Modifier] ++ return UISC == Syllable_Modifier ++def is_CONS_MED(U, UISC, UGC): ++ return UISC == Consonant_Medial and UGC != Lo ++def is_CONS_MOD(U, UISC, UGC): ++ return UISC in [Nukta, Gemination_Mark, Consonant_Killer] ++def is_CONS_SUB(U, UISC, UGC): ++ #SPEC-OUTDATED return UISC == Consonant_Subjoined ++ return UISC == Consonant_Subjoined and UGC != Lo ++def is_HALANT(U, UISC, UGC): ++ return UISC in [Virama, Invisible_Stacker] ++def is_HALANT_NUM(U, UISC, UGC): ++ return UISC == Number_Joiner ++def is_ZWNJ(U, UISC, UGC): ++ return UISC == Non_Joiner ++def is_ZWJ(U, UISC, UGC): ++ return UISC == Joiner ++def is_Word_Joiner(U, UISC, UGC): ++ return U == 0x2060 ++def is_OTHER(U, UISC, UGC): ++ #SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters ++ return (UISC == Other ++ and not is_SYM_MOD(U, UISC, UGC) ++ and not is_CGJ(U, UISC, UGC) ++ and not is_Word_Joiner(U, UISC, UGC) ++ and not is_VARIATION_SELECTOR(U, UISC, UGC) ++ ) ++def is_Reserved(U, UISC, UGC): ++ return UGC == 'Cn' ++def is_REPHA(U, UISC, UGC): ++ #return UISC == Consonant_Preceding_Repha ++ #SPEC-OUTDATED hack to categorize Consonant_With_Stacker and Consonant_Prefixed ++ return UISC in [Consonant_Preceding_Repha, Consonant_With_Stacker, Consonant_Prefixed] ++def is_SYM(U, UISC, UGC): ++ if U == 0x25CC: return False #SPEC-OUTDATED ++ #SPEC-OUTDATED return UGC in [So, Sc] or UISC == Symbol_Letter ++ return UGC in [So, Sc] ++def is_SYM_MOD(U, UISC, UGC): ++ return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73] ++def is_VARIATION_SELECTOR(U, UISC, UGC): ++ return 0xFE00 <= U <= 0xFE0F ++def is_VOWEL(U, UISC, UGC): ++ return (UISC == Pure_Killer or ++ (UGC != Lo and UISC in [Vowel, Vowel_Dependent])) ++def is_VOWEL_MOD(U, UISC, UGC): ++ return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or ++ (UGC != Lo and UISC == Bindu)) ++ ++use_mapping = { ++ 'B': is_BASE, ++ 'IV': is_BASE_VOWEL, ++ 'IND': is_BASE_IND, ++ 'N': is_BASE_NUM, ++ 'GB': is_BASE_OTHER, ++ 'CGJ': is_CGJ, ++ 'F': is_CONS_FINAL, ++ 'FM': is_CONS_FINAL_MOD, ++ 'M': is_CONS_MED, ++ 'CM': is_CONS_MOD, ++ 'SUB': is_CONS_SUB, ++ 'H': is_HALANT, ++ 'HN': is_HALANT_NUM, ++ 'ZWNJ': is_ZWNJ, ++ 'ZWJ': is_ZWJ, ++ 'WJ': is_Word_Joiner, ++ 'O': is_OTHER, ++ 'Rsv': is_Reserved, ++ 'R': is_REPHA, ++ 'S': is_SYM, ++ 'SM': is_SYM_MOD, ++ 'VS': is_VARIATION_SELECTOR, ++ 'V': is_VOWEL, ++ 'VM': is_VOWEL_MOD, ++} ++ ++use_positions = { ++ 'F': { ++ 'Abv': [Top], ++ 'Blw': [Bottom], ++ 'Pst': [Right], ++ }, ++ 'M': { ++ 'Abv': [Top], ++ 'Blw': [Bottom], ++ 'Pst': [Right], ++ 'Pre': [Left], ++ }, ++ 'CM': { ++ 'Abv': [Top], ++ 'Blw': [Bottom], ++ }, ++ 'V': { ++ 'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right], ++ 'Blw': [Bottom, Overstruck, Bottom_And_Right], ++ 'Pst': [Right], ++ 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], ++ }, ++ 'VM': { ++ 'Abv': [Top], ++ 'Blw': [Bottom, Overstruck], ++ 'Pst': [Right], ++ 'Pre': [Left], ++ }, ++ 'SM': { ++ 'Abv': [Top], ++ 'Blw': [Bottom], ++ }, ++ 'H': None, ++ 'B': None, ++ 'FM': None, ++ 'SUB': None, ++} ++ ++def map_to_use(data): ++ out = {} ++ items = use_mapping.items() ++ for U,(UISC,UIPC,UGC,UBlock) in data.items(): ++ ++ # Resolve Indic_Syllabic_Category ++ ++ # TODO: These don't have UISC assigned in Unicode 8.0, but ++ # have UIPC ++ if U == 0x17DD: UISC = Vowel_Dependent ++ if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark ++ ++ # TODO: U+1CED should only be allowed after some of ++ # the nasalization marks, maybe only for U+1CE9..U+1CF1. ++ if U == 0x1CED: UISC = Tone_Mark ++ ++ evals = [(k, v(U,UISC,UGC)) for k,v in items] ++ values = [k for k,v in evals if v] ++ assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values) ++ USE = values[0] ++ ++ # Resolve Indic_Positional_Category ++ ++ # TODO: Not in Unicode 8.0 yet, but in spec. ++ if U == 0x1B6C: UIPC = Bottom ++ ++ # TODO: These should die, but have UIPC in Unicode 8.0 ++ if U in [0x953, 0x954]: UIPC = Not_Applicable ++ ++ # TODO: In USE's override list but not in Unicode 8.0 ++ if U == 0x103C: UIPC = Left ++ ++ # TODO: These are not in USE's override list that we have, nor are they in Unicode 8.0 ++ if 0xA926 <= U <= 0xA92A: UIPC = Top ++ if U == 0x111CA: UIPC = Bottom ++ if U == 0x11300: UIPC = Top ++ if U == 0x1133C: UIPC = Bottom ++ if U == 0x1171E: UIPC = Left # Correct?! ++ if 0x1CF2 <= U <= 0x1CF3: UIPC = Right ++ if 0x1CF8 <= U <= 0x1CF9: UIPC = Top ++ ++ assert (UIPC in [Not_Applicable, Visual_Order_Left] or ++ USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC) ++ ++ pos_mapping = use_positions.get(USE, None) ++ if pos_mapping: ++ values = [k for k,v in pos_mapping.items() if v and UIPC in v] ++ assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values) ++ USE = USE + values[0] ++ ++ out[U] = (USE, UBlock) ++ return out ++ ++defaults = ('O', 'No_Block') ++data = map_to_use(data) ++ ++# Remove the outliers ++singles = {} ++for u in [0x034F, 0x25CC, 0x1107F]: ++ singles[u] = data[u] ++ del data[u] ++ ++print "/* == Start of generated table == */" ++print "/*" ++print " * The following table is generated by running:" ++print " *" ++print " * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt" ++print " *" ++print " * on files with these headers:" ++print " *" ++for h in headers: ++ for l in h: ++ print " * %s" % (l.strip()) ++print " */" ++print ++print '#include "hb-ot-shape-complex-use-private.hh"' ++print ++ ++total = 0 ++used = 0 ++last_block = None ++def print_block (block, start, end, data): ++ global total, used, last_block ++ if block and block != last_block: ++ print ++ print ++ print " /* %s */" % block ++ if start % 16: ++ print ' ' * (20 + (start % 16 * 6)), ++ num = 0 ++ assert start % 8 == 0 ++ assert (end+1) % 8 == 0 ++ for u in range (start, end+1): ++ if u % 16 == 0: ++ print ++ print " /* %04X */" % u, ++ if u in data: ++ num += 1 ++ d = data.get (u, defaults) ++ sys.stdout.write ("%6s," % d[0]) ++ ++ total += end - start + 1 ++ used += num ++ if block: ++ last_block = block ++ ++uu = data.keys () ++uu.sort () ++ ++last = -100000 ++num = 0 ++offset = 0 ++starts = [] ++ends = [] ++for k,v in sorted(use_mapping.items()): ++ if k in use_positions and use_positions[k]: continue ++ print "#define %s USE_%s /* %s */" % (k, k, v.__name__[3:]) ++for k,v in sorted(use_positions.items()): ++ if not v: continue ++ for suf in v.keys(): ++ tag = k + suf ++ print "#define %s USE_%s" % (tag, tag) ++print "" ++print "static const USE_TABLE_ELEMENT_TYPE use_table[] = {" ++for u in uu: ++ if u <= last: ++ continue ++ block = data[u][1] ++ ++ start = u//8*8 ++ end = start+1 ++ while end in uu and block == data[end][1]: ++ end += 1 ++ end = (end-1)//8*8 + 7 ++ ++ if start != last + 1: ++ if start - last <= 1+16*3: ++ print_block (None, last+1, start-1, data) ++ last = start-1 ++ else: ++ if last >= 0: ++ ends.append (last + 1) ++ offset += ends[-1] - starts[-1] ++ print ++ print ++ print "#define use_offset_0x%04xu %d" % (start, offset) ++ starts.append (start) ++ ++ print_block (block, start, end, data) ++ last = end ++ends.append (last + 1) ++offset += ends[-1] - starts[-1] ++print ++print ++occupancy = used * 100. / total ++page_bits = 12 ++print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy) ++print ++print "USE_TABLE_ELEMENT_TYPE" ++print "hb_use_get_categories (hb_codepoint_t u)" ++print "{" ++print " switch (u >> %d)" % page_bits ++print " {" ++pages = set([u>>page_bits for u in starts+ends+singles.keys()]) ++for p in sorted(pages): ++ print " case 0x%0Xu:" % p ++ for (start,end) in zip (starts, ends): ++ if p not in [start>>page_bits, end>>page_bits]: continue ++ offset = "use_offset_0x%04xu" % start ++ print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset) ++ for u,d in singles.items (): ++ if p != u>>page_bits: continue ++ print " if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0]) ++ print " break;" ++ print "" ++print " default:" ++print " break;" ++print " }" ++print " return USE_O;" ++print "}" ++print ++for k in sorted(use_mapping.keys()): ++ if k in use_positions and use_positions[k]: continue ++ print "#undef %s" % k ++for k,v in sorted(use_positions.items()): ++ if not v: continue ++ for suf in v.keys(): ++ tag = k + suf ++ print "#undef %s" % tag ++print ++print "/* == End of generated table == */" ++ ++# Maintain at least 50% occupancy in the table */ ++if occupancy < 50: ++ raise Exception ("Table too sparse, please investigate: ", occupancy) +diff -uN gfx/harfbuzz/src_old/harfbuzz-icu.pc gfx/harfbuzz/src/harfbuzz-icu.pc +--- gfx/harfbuzz/src_old/harfbuzz-icu.pc 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/harfbuzz-icu.pc 2016-06-05 23:48:12.049392976 +0200 +@@ -0,0 +1,13 @@ ++prefix=/usr/local ++exec_prefix=/usr/local ++libdir=/usr/local/lib ++includedir=/usr/local/include ++ ++Name: harfbuzz ++Description: HarfBuzz text shaping library ICU integration ++Version: 1.0.1 ++ ++Requires: harfbuzz ++Requires.private: icu-uc ++Libs: -L${libdir} -lharfbuzz-icu ++Cflags: -I${includedir}/harfbuzz +diff -uN gfx/harfbuzz/src_old/harfbuzz.pc gfx/harfbuzz/src/harfbuzz.pc +--- gfx/harfbuzz/src_old/harfbuzz.pc 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/harfbuzz.pc 2016-06-05 23:48:14.499379160 +0200 +@@ -0,0 +1,11 @@ ++prefix=/usr/local ++exec_prefix=/usr/local ++libdir=/usr/local/lib ++includedir=/usr/local/include ++ ++Name: harfbuzz ++Description: HarfBuzz text shaping library ++Version: 1.0.1 ++ ++Libs: -L${libdir} -lharfbuzz ++Cflags: -I${includedir}/harfbuzz +diff -uN gfx/harfbuzz/src_old/harfbuzz.pc.in gfx/harfbuzz/src/harfbuzz.pc.in +--- gfx/harfbuzz/src_old/harfbuzz.pc.in 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/harfbuzz.pc.in 2016-06-05 23:48:15.731372204 +0200 +@@ -8,4 +8,6 @@ + Version: %VERSION% + + Libs: -L${libdir} -lharfbuzz ++Libs.private: %libs_private% ++Requires.private: %requires_private% + Cflags: -I${includedir}/harfbuzz +diff -uN gfx/harfbuzz/src_old/hb-atomic-private.hh gfx/harfbuzz/src/hb-atomic-private.hh +--- gfx/harfbuzz/src_old/hb-atomic-private.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-atomic-private.hh 2016-06-05 23:48:16.918365513 +0200 +@@ -39,7 +39,11 @@ + + /* We need external help for these */ + +-#if 0 ++#if defined(hb_atomic_int_impl_add) \ ++ && defined(hb_atomic_ptr_impl_get) \ ++ && defined(hb_atomic_ptr_impl_cmpexch) ++ ++/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */ + + + #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) +@@ -58,11 +62,12 @@ + #endif + } + +-typedef LONG hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) ++typedef LONG hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) + +-#define hb_atomic_ptr_get(P) (_HBMemoryBarrier (), (void *) *(P)) +-#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) ++#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) + + + #elif !defined(HB_NO_MT) && defined(__APPLE__) +@@ -74,28 +79,31 @@ + #include + #endif + +-typedef int32_t hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) + +-#define hb_atomic_ptr_get(P) (OSMemoryBarrier (), (void *) *(P)) ++typedef int32_t hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) ++ ++#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P)) + #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) +-#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) + #else + #if __ppc64__ || __x86_64__ || __aarch64__ +-#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) + #else +-#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) + #endif + #endif + + + #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) + +-typedef int hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) __sync_fetch_and_add (&(AI), (V)) ++typedef int hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V)) + +-#define hb_atomic_ptr_get(P) (void *) (__sync_synchronize (), *(P)) +-#define hb_atomic_ptr_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) ++#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) + + + #elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) +@@ -103,33 +111,79 @@ + #include + #include + +-typedef unsigned int hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V)) ++typedef unsigned int hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V)) ++ ++#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false) ++ ++ ++#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__) ++ ++#include ++ ++ ++static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) { ++ __lwsync(); ++ int result = __fetch_and_add(AI, V); ++ __isync(); ++ return result; ++} ++static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) { ++ __sync(); ++ int result = __compare_and_swaplp (P, &O, N); ++ __sync(); ++ return result; ++} + +-#define hb_atomic_ptr_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P)) +-#define hb_atomic_ptr_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false) ++typedef int hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V)) + ++#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N)) + + #elif !defined(HB_NO_MT) + + #define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ +-typedef volatile int hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) (((AI) += (V)) - (V)) + +-#define hb_atomic_ptr_get(P) ((void *) *(P)) +-#define hb_atomic_ptr_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false) ++typedef volatile int hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) ++ ++#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false) + + + #else /* HB_NO_MT */ + +-typedef int hb_atomic_int_t; +-#define hb_atomic_int_add(AI, V) (((AI) += (V)) - (V)) ++typedef int hb_atomic_int_impl_t; ++#define HB_ATOMIC_INT_IMPL_INIT(V) (V) ++#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V)) ++ ++#define hb_atomic_ptr_impl_get(P) ((void *) *(P)) ++#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) + +-#define hb_atomic_ptr_get(P) ((void *) *(P)) +-#define hb_atomic_ptr_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) + + #endif + +-/* TODO Add tracing. */ ++ ++#define HB_ATOMIC_INT_INIT(V) {HB_ATOMIC_INT_IMPL_INIT(V)} ++ ++struct hb_atomic_int_t ++{ ++ hb_atomic_int_impl_t v; ++ ++ inline void set_unsafe (int v_) { v = v_; } ++ inline int get_unsafe (void) const { return v; } ++ inline int inc (void) { return hb_atomic_int_impl_add (const_cast (v), 1); } ++ inline int dec (void) { return hb_atomic_int_impl_add (const_cast (v), -1); } ++}; ++ ++ ++#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P) ++#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N)) ++ + + #endif /* HB_ATOMIC_PRIVATE_HH */ +diff -uN gfx/harfbuzz/src_old/hb-blob.cc gfx/harfbuzz/src/hb-blob.cc +--- gfx/harfbuzz/src_old/hb-blob.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-blob.cc 2016-06-05 23:48:18.064359059 +0200 +@@ -78,8 +78,8 @@ + } + + /** +- * hb_blob_create: (Xconstructor) +- * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data. ++ * hb_blob_create: (skip) ++ * @data: Pointer to blob data. + * @length: Length of @data in bytes. + * @mode: Memory mode for @data. + * @user_data: Data parameter to pass to @destroy. +@@ -91,7 +91,7 @@ + * Return value: New blob, or the empty blob if something failed or if @length is + * zero. Destroy with hb_blob_destroy(). + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_blob_create (const char *data, +@@ -147,7 +147,7 @@ + * @length is zero or @offset is beyond the end of @parent's data. Destroy + * with hb_blob_destroy(). + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_blob_create_sub_blob (hb_blob_t *parent, +@@ -179,7 +179,7 @@ + * + * Return value: (transfer full): the empty blob. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_blob_get_empty (void) +@@ -210,7 +210,7 @@ + * + * Return value: @blob. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_blob_reference (hb_blob_t *blob) +@@ -228,7 +228,7 @@ + * + * See TODO:link object types for more information. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_blob_destroy (hb_blob_t *blob) +@@ -250,7 +250,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_blob_set_user_data (hb_blob_t *blob, +@@ -271,7 +271,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void * + hb_blob_get_user_data (hb_blob_t *blob, +@@ -287,7 +287,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_blob_make_immutable (hb_blob_t *blob) +@@ -306,7 +306,7 @@ + * + * Return value: TODO + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_blob_is_immutable (hb_blob_t *blob) +@@ -323,7 +323,7 @@ + * + * Return value: the length of blob data in bytes. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + unsigned int + hb_blob_get_length (hb_blob_t *blob) +@@ -340,7 +340,7 @@ + * + * Returns: (transfer none) (array length=length): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + const char * + hb_blob_get_data (hb_blob_t *blob, unsigned int *length) +@@ -365,7 +365,7 @@ + * Returns: (transfer none) (array length=length): Writable blob data, + * or %NULL if failed. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + char * + hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) +diff -uN gfx/harfbuzz/src_old/hb-blob.h gfx/harfbuzz/src/hb-blob.h +--- gfx/harfbuzz/src_old/hb-blob.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-blob.h 2016-06-05 23:48:19.231352500 +0200 +@@ -64,7 +64,7 @@ + + typedef struct hb_blob_t hb_blob_t; + +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_blob_create (const char *data, + unsigned int length, + hb_memory_mode_t mode, +@@ -77,21 +77,21 @@ + * modify the parent data as that data may be + * shared among multiple sub-blobs. + */ +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_blob_create_sub_blob (hb_blob_t *parent, + unsigned int offset, + unsigned int length); + +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_blob_get_empty (void); + +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_blob_reference (hb_blob_t *blob); + +-void ++HB_EXTERN void + hb_blob_destroy (hb_blob_t *blob); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_blob_set_user_data (hb_blob_t *blob, + hb_user_data_key_t *key, + void * data, +@@ -99,25 +99,25 @@ + hb_bool_t replace); + + +-void * ++HB_EXTERN void * + hb_blob_get_user_data (hb_blob_t *blob, + hb_user_data_key_t *key); + + +-void ++HB_EXTERN void + hb_blob_make_immutable (hb_blob_t *blob); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_blob_is_immutable (hb_blob_t *blob); + + +-unsigned int ++HB_EXTERN unsigned int + hb_blob_get_length (hb_blob_t *blob); + +-const char * ++HB_EXTERN const char * + hb_blob_get_data (hb_blob_t *blob, unsigned int *length); + +-char * ++HB_EXTERN char * + hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length); + + +diff -uN gfx/harfbuzz/src_old/hb-buffer.cc gfx/harfbuzz/src/hb-buffer.cc +--- gfx/harfbuzz/src_old/hb-buffer.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer.cc 2016-06-05 23:48:28.261301901 +0200 +@@ -35,7 +35,28 @@ + #define HB_DEBUG_BUFFER (HB_DEBUG+0) + #endif + ++/** ++ * SECTION: hb-buffer ++ * @title: Buffers ++ * @short_description: Input and output buffers ++ * @include: hb.h ++ * ++ * Buffers serve dual role in HarfBuzz; they hold the input characters that are ++ * passed hb_shape(), and after shaping they hold the output glyphs. ++ **/ + ++/** ++ * hb_segment_properties_equal: ++ * @a: first #hb_segment_properties_t to compare. ++ * @b: second #hb_segment_properties_t to compare. ++ * ++ * Checks the equality of two #hb_segment_properties_t's. ++ * ++ * Return value: (transfer full): ++ * %true if all properties of @a equal those of @b, false otherwise. ++ * ++ * Since: 0.9.7 ++ **/ + hb_bool_t + hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b) +@@ -48,6 +69,17 @@ + + } + ++/** ++ * hb_segment_properties_hash: ++ * @p: #hb_segment_properties_t to hash. ++ * ++ * Creates a hash representing @p. ++ * ++ * Return value: ++ * A hash of @p. ++ * ++ * Since: 0.9.7 ++ **/ + unsigned int + hb_segment_properties_hash (const hb_segment_properties_t *p) + { +@@ -85,6 +117,11 @@ + { + if (unlikely (in_error)) + return false; ++ if (unlikely (size > max_len)) ++ { ++ in_error = true; ++ return false; ++ } + + unsigned int new_allocated = allocated; + hb_glyph_position_t *new_pos = NULL; +@@ -192,6 +229,7 @@ + + hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; + props = default_props; ++ scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; + + content_type = HB_BUFFER_CONTENT_TYPE_INVALID; + in_error = false; +@@ -443,7 +481,7 @@ + { + unsigned int i, j; + +- if (start == end - 1) ++ if (end - start < 2) + return; + + for (i = start, j = end - 1; i < j; i++, j--) { +@@ -454,7 +492,7 @@ + info[j] = t; + } + +- if (pos) { ++ if (have_positions) { + for (i = start, j = end - 1; i < j; i++, j--) { + hb_glyph_position_t t; + +@@ -498,14 +536,10 @@ + } + + void +-hb_buffer_t::merge_clusters (unsigned int start, +- unsigned int end) ++hb_buffer_t::merge_clusters_impl (unsigned int start, ++ unsigned int end) + { +-#ifdef HB_NO_MERGE_CLUSTERS +- return; +-#endif +- +- if (unlikely (end - start < 2)) ++ if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + return; + + unsigned int cluster = info[start].cluster; +@@ -523,7 +557,7 @@ + + /* If we hit the start of buffer, continue in out-buffer. */ + if (idx == start) +- for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) ++ for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) + out_info[i - 1].cluster = cluster; + + for (unsigned int i = start; i < end; i++) +@@ -533,9 +567,8 @@ + hb_buffer_t::merge_out_clusters (unsigned int start, + unsigned int end) + { +-#ifdef HB_NO_MERGE_CLUSTERS +- return; +-#endif ++ if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) ++ return; + + if (unlikely (end - start < 2)) + return; +@@ -555,12 +588,44 @@ + + /* If we hit the end of out-buffer, continue in buffer. */ + if (end == out_len) +- for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) ++ for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++) + info[i].cluster = cluster; + + for (unsigned int i = start; i < end; i++) + out_info[i].cluster = cluster; + } ++void ++hb_buffer_t::delete_glyph () ++{ ++ unsigned int cluster = info[idx].cluster; ++ if (idx + 1 < len && cluster == info[idx + 1].cluster) ++ { ++ /* Cluster survives; do nothing. */ ++ goto done; ++ } ++ ++ if (out_len) ++ { ++ /* Merge cluster backward. */ ++ if (cluster < out_info[out_len - 1].cluster) ++ { ++ unsigned int old_cluster = out_info[out_len - 1].cluster; ++ for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--) ++ out_info[i - 1].cluster = cluster; ++ } ++ goto done; ++ } ++ ++ if (idx + 1 < len) ++ { ++ /* Merge cluster forward. */ ++ merge_clusters (idx, idx + 2); ++ goto done; ++ } ++ ++done: ++ skip_glyph (); ++} + + void + hb_buffer_t::guess_segment_properties (void) +@@ -667,11 +732,16 @@ + /** + * hb_buffer_create: (Xconstructor) + * +- * ++ * Creates a new #hb_buffer_t with all properties to defaults. + * +- * Return value: (transfer full) ++ * Return value: (transfer full): ++ * A newly allocated #hb_buffer_t with a reference count of 1. The initial ++ * reference count should be released with hb_buffer_destroy() when you are done ++ * using the #hb_buffer_t. This function never returns %NULL. If memory cannot ++ * be allocated, a special #hb_buffer_t object will be returned on which ++ * hb_buffer_allocation_successful() returns %false. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_buffer_t * + hb_buffer_create (void) +@@ -681,6 +751,8 @@ + if (!(buffer = hb_object_create ())) + return hb_buffer_get_empty (); + ++ buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; ++ + buffer->reset (); + + return buffer; +@@ -693,7 +765,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_buffer_t * + hb_buffer_get_empty (void) +@@ -703,7 +775,10 @@ + + const_cast (&_hb_unicode_funcs_nil), + HB_BUFFER_FLAG_DEFAULT, ++ HB_BUFFER_CLUSTER_LEVEL_DEFAULT, + HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, ++ HB_BUFFER_SCRATCH_FLAG_DEFAULT, ++ HB_BUFFER_MAX_LEN_DEFAULT, + + HB_BUFFER_CONTENT_TYPE_INVALID, + HB_SEGMENT_PROPERTIES_DEFAULT, +@@ -719,13 +794,15 @@ + + /** + * hb_buffer_reference: (skip) +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Increases the reference count on @buffer by one. This prevents @buffer from ++ * being destroyed until a matching call to hb_buffer_destroy() is made. + * + * Return value: (transfer full): ++ * The referenced #hb_buffer_t. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_buffer_t * + hb_buffer_reference (hb_buffer_t *buffer) +@@ -735,11 +812,13 @@ + + /** + * hb_buffer_destroy: (skip) +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Deallocate the @buffer. ++ * Decreases the reference count on @buffer by one. If the result is zero, then ++ * @buffer and all associated resources are freed. See hb_buffer_reference(). + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_destroy (hb_buffer_t *buffer) +@@ -750,13 +829,15 @@ + + free (buffer->info); + free (buffer->pos); ++ if (buffer->message_destroy) ++ buffer->message_destroy (buffer->message_data); + + free (buffer); + } + + /** + * hb_buffer_set_user_data: (skip) +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * @key: + * @data: + * @destroy: +@@ -766,7 +847,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_buffer_set_user_data (hb_buffer_t *buffer, +@@ -780,14 +861,14 @@ + + /** + * hb_buffer_get_user_data: (skip) +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * @key: + * + * + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void * + hb_buffer_get_user_data (hb_buffer_t *buffer, +@@ -799,12 +880,13 @@ + + /** + * hb_buffer_set_content_type: +- * @buffer: a buffer. +- * @content_type: ++ * @buffer: an #hb_buffer_t. ++ * @content_type: the type of buffer contents to set + * +- * ++ * Sets the type of @buffer contents, buffers are either empty, contain ++ * characters (before shaping) or glyphs (the result of shaping). + * +- * Since: 1.0 ++ * Since: 0.9.5 + **/ + void + hb_buffer_set_content_type (hb_buffer_t *buffer, +@@ -815,13 +897,14 @@ + + /** + * hb_buffer_get_content_type: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * see hb_buffer_set_content_type(). + * +- * Return value: ++ * Return value: ++ * The type of @buffer contents. + * +- * Since: 1.0 ++ * Since: 0.9.5 + **/ + hb_buffer_content_type_t + hb_buffer_get_content_type (hb_buffer_t *buffer) +@@ -832,12 +915,12 @@ + + /** + * hb_buffer_set_unicode_funcs: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * @unicode_funcs: + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, +@@ -857,13 +940,13 @@ + + /** + * hb_buffer_get_unicode_funcs: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * + * + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_unicode_funcs_t * + hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) +@@ -873,12 +956,18 @@ + + /** + * hb_buffer_set_direction: +- * @buffer: a buffer. +- * @direction: ++ * @buffer: an #hb_buffer_t. ++ * @direction: the #hb_direction_t of the @buffer + * +- * ++ * Set the text flow direction of the buffer. No shaping can happen without ++ * setting @buffer direction, and it controls the visual direction for the ++ * output glyphs; for RTL direction the glyphs will be reversed. Many layout ++ * features depend on the proper setting of the direction, for example, ++ * reversing RTL text before shaping, then shaping with LTR direction is not ++ * the same as keeping the text in logical order and shaping with RTL ++ * direction. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_set_direction (hb_buffer_t *buffer, +@@ -893,13 +982,14 @@ + + /** + * hb_buffer_get_direction: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * See hb_buffer_set_direction() + * +- * Return value: ++ * Return value: ++ * The direction of the @buffer. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_direction_t + hb_buffer_get_direction (hb_buffer_t *buffer) +@@ -909,12 +999,20 @@ + + /** + * hb_buffer_set_script: +- * @buffer: a buffer. +- * @script: ++ * @buffer: an #hb_buffer_t. ++ * @script: an #hb_script_t to set. + * +- * ++ * Sets the script of @buffer to @script. + * +- * Since: 1.0 ++ * Script is crucial for choosing the proper shaping behaviour for scripts that ++ * require it (e.g. Arabic) and the which OpenType features defined in the font ++ * to be applied. ++ * ++ * You can pass one of the predefined #hb_script_t values, or use ++ * hb_script_from_string() or hb_script_from_iso15924_tag() to get the ++ * corresponding script from an ISO 15924 script tag. ++ * ++ * Since: 0.9.2 + **/ + void + hb_buffer_set_script (hb_buffer_t *buffer, +@@ -928,13 +1026,14 @@ + + /** + * hb_buffer_get_script: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * See hb_buffer_set_script(). + * +- * Return value: ++ * Return value: ++ * The #hb_script_t of the @buffer. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_script_t + hb_buffer_get_script (hb_buffer_t *buffer) +@@ -944,12 +1043,20 @@ + + /** + * hb_buffer_set_language: +- * @buffer: a buffer. +- * @language: ++ * @buffer: an #hb_buffer_t. ++ * @language: an hb_language_t to set. + * +- * ++ * Sets the language of @buffer to @language. ++ * ++ * Languages are crucial for selecting which OpenType feature to apply to the ++ * buffer which can result in applying language-specific behaviour. Languages ++ * are orthogonal to the scripts, and though they are related, they are ++ * different concepts and should not be confused with each other. ++ * ++ * Use hb_language_from_string() to convert from ISO 639 language codes to ++ * #hb_language_t. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_set_language (hb_buffer_t *buffer, +@@ -963,13 +1070,14 @@ + + /** + * hb_buffer_get_language: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * See hb_buffer_set_language(). + * +- * Return value: ++ * Return value: (transfer none): ++ * The #hb_language_t of the buffer. Must not be freed by the caller. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_language_t + hb_buffer_get_language (hb_buffer_t *buffer) +@@ -979,12 +1087,14 @@ + + /** + * hb_buffer_set_segment_properties: +- * @buffer: a buffer. +- * @props: ++ * @buffer: an #hb_buffer_t. ++ * @props: an #hb_segment_properties_t to use. + * +- * ++ * Sets the segment properties of the buffer, a shortcut for calling ++ * hb_buffer_set_direction(), hb_buffer_set_script() and ++ * hb_buffer_set_language() individually. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_buffer_set_segment_properties (hb_buffer_t *buffer, +@@ -998,12 +1108,12 @@ + + /** + * hb_buffer_get_segment_properties: +- * @buffer: a buffer. +- * @props: ++ * @buffer: an #hb_buffer_t. ++ * @props: (out): the output #hb_segment_properties_t. + * +- * ++ * Sets @props to the #hb_segment_properties_t of @buffer. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_buffer_get_segment_properties (hb_buffer_t *buffer, +@@ -1015,12 +1125,12 @@ + + /** + * hb_buffer_set_flags: +- * @buffer: a buffer. +- * @flags: ++ * @buffer: an #hb_buffer_t. ++ * @flags: the buffer flags to set. + * +- * ++ * Sets @buffer flags to @flags. See #hb_buffer_flags_t. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_buffer_set_flags (hb_buffer_t *buffer, +@@ -1034,13 +1144,14 @@ + + /** + * hb_buffer_get_flags: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * See hb_buffer_set_flags(). + * + * Return value: ++ * The @buffer flags. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + hb_buffer_flags_t + hb_buffer_get_flags (hb_buffer_t *buffer) +@@ -1048,15 +1159,53 @@ + return buffer->flags; + } + ++/** ++ * hb_buffer_set_cluster_level: ++ * @buffer: an #hb_buffer_t. ++ * @cluster_level: ++ * ++ * ++ * ++ * Since: 0.9.42 ++ **/ ++void ++hb_buffer_set_cluster_level (hb_buffer_t *buffer, ++ hb_buffer_cluster_level_t cluster_level) ++{ ++ if (unlikely (hb_object_is_inert (buffer))) ++ return; ++ ++ buffer->cluster_level = cluster_level; ++} ++ ++/** ++ * hb_buffer_get_cluster_level: ++ * @buffer: an #hb_buffer_t. ++ * ++ * ++ * ++ * Return value: ++ * ++ * Since: 0.9.42 ++ **/ ++hb_buffer_cluster_level_t ++hb_buffer_get_cluster_level (hb_buffer_t *buffer) ++{ ++ return buffer->cluster_level; ++} ++ + + /** + * hb_buffer_set_replacement_codepoint: +- * @buffer: a buffer. +- * @replacement: ++ * @buffer: an #hb_buffer_t. ++ * @replacement: the replacement #hb_codepoint_t + * +- * ++ * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding ++ * when adding text to @buffer. + * +- * Since: 1.0 ++ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT. ++ * ++ * Since: 0.9.31 + **/ + void + hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, +@@ -1070,13 +1219,14 @@ + + /** + * hb_buffer_get_replacement_codepoint: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * See hb_buffer_set_replacement_codepoint(). + * + * Return value: ++ * The @buffer replacement #hb_codepoint_t. + * +- * Since: 1.0 ++ * Since: 0.9.31 + **/ + hb_codepoint_t + hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) +@@ -1087,11 +1237,12 @@ + + /** + * hb_buffer_reset: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Resets the buffer to its initial status, as if it was just newly created ++ * with hb_buffer_create(). + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_reset (hb_buffer_t *buffer) +@@ -1101,11 +1252,12 @@ + + /** + * hb_buffer_clear_contents: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Similar to hb_buffer_reset(), but does not clear the Unicode functions and ++ * the replacement code point. + * +- * Since: 1.0 ++ * Since: 0.9.11 + **/ + void + hb_buffer_clear_contents (hb_buffer_t *buffer) +@@ -1115,14 +1267,15 @@ + + /** + * hb_buffer_pre_allocate: +- * @buffer: a buffer. +- * @size: ++ * @buffer: an #hb_buffer_t. ++ * @size: number of items to pre allocate. + * +- * ++ * Pre allocates memory for @buffer to fit at least @size number of items. + * +- * Return value: ++ * Return value: ++ * %true if @buffer memory allocation succeeded, %false otherwise. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) +@@ -1132,13 +1285,14 @@ + + /** + * hb_buffer_allocation_successful: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Check if allocating memory for the buffer succeeded. + * +- * Return value: ++ * Return value: ++ * %true if @buffer memory allocation succeeded, %false otherwise. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_buffer_allocation_successful (hb_buffer_t *buffer) +@@ -1148,13 +1302,20 @@ + + /** + * hb_buffer_add: +- * @buffer: a buffer. +- * @codepoint: +- * @cluster: ++ * @buffer: an #hb_buffer_t. ++ * @codepoint: a Unicode code point. ++ * @cluster: the cluster value of @codepoint. ++ * ++ * Appends a character with the Unicode value of @codepoint to @buffer, and ++ * gives it the initial cluster value of @cluster. Clusters can be any thing ++ * the client wants, they are usually used to refer to the index of the ++ * character in the input text stream and are output in ++ * #hb_glyph_info_t.cluster field. + * +- * ++ * This function does not check the validity of @codepoint, it is up to the ++ * caller to ensure it is a valid Unicode code point. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_buffer_add (hb_buffer_t *buffer, +@@ -1167,14 +1328,16 @@ + + /** + * hb_buffer_set_length: +- * @buffer: a buffer. +- * @length: ++ * @buffer: an #hb_buffer_t. ++ * @length: the new length of @buffer. + * +- * ++ * Similar to hb_buffer_pre_allocate(), but clears any new items added at the ++ * end. + * + * Return value: ++ * %true if @buffer memory allocation succeeded, %false otherwise. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_buffer_set_length (hb_buffer_t *buffer, +@@ -1207,13 +1370,15 @@ + + /** + * hb_buffer_get_length: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * + * Returns the number of items in the buffer. + * +- * Return value: buffer length. ++ * Return value: ++ * The @buffer length. ++ * The value valid as long as buffer has not been modified. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + unsigned int + hb_buffer_get_length (hb_buffer_t *buffer) +@@ -1223,15 +1388,17 @@ + + /** + * hb_buffer_get_glyph_infos: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * @length: (out): output array length. + * +- * Returns buffer glyph information array. Returned pointer +- * is valid as long as buffer contents are not modified. ++ * Returns @buffer glyph information array. Returned pointer ++ * is valid as long as @buffer contents are not modified. + * +- * Return value: (transfer none) (array length=length): buffer glyph information array. ++ * Return value: (transfer none) (array length=length): ++ * The @buffer glyph information array. ++ * The value valid as long as buffer has not been modified. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_glyph_info_t * + hb_buffer_get_glyph_infos (hb_buffer_t *buffer, +@@ -1245,15 +1412,17 @@ + + /** + * hb_buffer_get_glyph_positions: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * @length: (out): output length. + * +- * Returns buffer glyph position array. Returned pointer +- * is valid as long as buffer contents are not modified. ++ * Returns @buffer glyph position array. Returned pointer ++ * is valid as long as @buffer contents are not modified. + * +- * Return value: (transfer none) (array length=length): buffer glyph position array. ++ * Return value: (transfer none) (array length=length): ++ * The @buffer glyph position array. ++ * The value valid as long as buffer has not been modified. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_glyph_position_t * + hb_buffer_get_glyph_positions (hb_buffer_t *buffer, +@@ -1270,11 +1439,11 @@ + + /** + * hb_buffer_reverse: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * + * Reverses buffer contents. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_reverse (hb_buffer_t *buffer) +@@ -1283,14 +1452,31 @@ + } + + /** ++ * hb_buffer_reverse_range: ++ * @buffer: an #hb_buffer_t. ++ * @start: start index. ++ * @end: end index. ++ * ++ * Reverses buffer contents between start to end. ++ * ++ * Since: 0.9.41 ++ **/ ++void ++hb_buffer_reverse_range (hb_buffer_t *buffer, ++ unsigned int start, unsigned int end) ++{ ++ buffer->reverse_range (start, end); ++} ++ ++/** + * hb_buffer_reverse_clusters: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * + * Reverses buffer clusters. That is, the buffer contents are + * reversed, then each cluster (consecutive items having the + * same cluster number) are reversed again. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_buffer_reverse_clusters (hb_buffer_t *buffer) +@@ -1300,7 +1486,7 @@ + + /** + * hb_buffer_guess_segment_properties: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * + * Sets unset buffer segment properties based on buffer Unicode + * contents. If buffer is not empty, it must have content type +@@ -1320,7 +1506,7 @@ + * hb_language_get_default(). This may change in the future by + * taking buffer script into consideration when choosing a language. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_buffer_guess_segment_properties (hb_buffer_t *buffer) +@@ -1328,15 +1514,15 @@ + buffer->guess_segment_properties (); + } + +-template ++template + static inline void + hb_buffer_add_utf (hb_buffer_t *buffer, +- const T *text, ++ const typename utf_t::codepoint_t *text, + int text_length, + unsigned int item_offset, + int item_length) + { +- typedef hb_utf_t utf_t; ++ typedef typename utf_t::codepoint_t T; + const hb_codepoint_t replacement = buffer->replacement; + + assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || +@@ -1399,15 +1585,20 @@ + + /** + * hb_buffer_add_utf8: +- * @buffer: a buffer. +- * @text: (array length=text_length): +- * @text_length: +- * @item_offset: +- * @item_length: ++ * @buffer: an #hb_buffer_t. ++ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 ++ * characters to append. ++ * @text_length: the length of the @text, or -1 if it is %NULL terminated. ++ * @item_offset: the offset of the first character to add to the @buffer. ++ * @item_length: the number of characters to add to the @buffer, or -1 for the ++ * end of @text (assuming it is %NULL terminated). + * +- * ++ * See hb_buffer_add_codepoints(). + * +- * Since: 1.0 ++ * Replaces invalid UTF-8 characters with the @buffer replacement code point, ++ * see hb_buffer_set_replacement_codepoint(). ++ * ++ * Since: 0.9.2 + **/ + void + hb_buffer_add_utf8 (hb_buffer_t *buffer, +@@ -1416,20 +1607,24 @@ + unsigned int item_offset, + int item_length) + { +- hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); ++ hb_buffer_add_utf (buffer, (const uint8_t *) text, text_length, item_offset, item_length); + } + + /** + * hb_buffer_add_utf16: +- * @buffer: a buffer. +- * @text: (array length=text_length): +- * @text_length: +- * @item_offset: +- * @item_length: ++ * @buffer: an #hb_buffer_t. ++ * @text: (array length=text_length): an array of UTF-16 characters to append. ++ * @text_length: the length of the @text, or -1 if it is %NULL terminated. ++ * @item_offset: the offset of the first character to add to the @buffer. ++ * @item_length: the number of characters to add to the @buffer, or -1 for the ++ * end of @text (assuming it is %NULL terminated). + * +- * ++ * See hb_buffer_add_codepoints(). + * +- * Since: 1.0 ++ * Replaces invalid UTF-16 characters with the @buffer replacement code point, ++ * see hb_buffer_set_replacement_codepoint(). ++ * ++ * Since: 0.9.2 + **/ + void + hb_buffer_add_utf16 (hb_buffer_t *buffer, +@@ -1438,20 +1633,24 @@ + unsigned int item_offset, + int item_length) + { +- hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); ++ hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); + } + + /** + * hb_buffer_add_utf32: +- * @buffer: a buffer. +- * @text: (array length=text_length): +- * @text_length: +- * @item_offset: +- * @item_length: ++ * @buffer: an #hb_buffer_t. ++ * @text: (array length=text_length): an array of UTF-32 characters to append. ++ * @text_length: the length of the @text, or -1 if it is %NULL terminated. ++ * @item_offset: the offset of the first character to add to the @buffer. ++ * @item_length: the number of characters to add to the @buffer, or -1 for the ++ * end of @text (assuming it is %NULL terminated). + * +- * ++ * See hb_buffer_add_codepoints(). + * +- * Since: 1.0 ++ * Replaces invalid UTF-32 characters with the @buffer replacement code point, ++ * see hb_buffer_set_replacement_codepoint(). ++ * ++ * Since: 0.9.2 + **/ + void + hb_buffer_add_utf32 (hb_buffer_t *buffer, +@@ -1460,20 +1659,59 @@ + unsigned int item_offset, + int item_length) + { +- hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); ++ hb_buffer_add_utf > (buffer, text, text_length, item_offset, item_length); ++} ++ ++/** ++ * hb_buffer_add_latin1: ++ * @buffer: an #hb_buffer_t. ++ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 ++ * characters to append. ++ * @text_length: the length of the @text, or -1 if it is %NULL terminated. ++ * @item_offset: the offset of the first character to add to the @buffer. ++ * @item_length: the number of characters to add to the @buffer, or -1 for the ++ * end of @text (assuming it is %NULL terminated). ++ * ++ * Similar to hb_buffer_add_codepoints(), but allows only access to first 256 ++ * Unicode code points that can fit in 8-bit strings. ++ * ++ * Has nothing to do with non-Unicode Latin-1 encoding. ++ * ++ * 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 (buffer, text, text_length, item_offset, item_length); + } + + /** + * hb_buffer_add_codepoints: +- * @buffer: a buffer. +- * @text: (array length=text_length): +- * @text_length: +- * @item_offset: +- * @item_length: ++ * @buffer: a #hb_buffer_t to append characters to. ++ * @text: (array length=text_length): an array of Unicode code points to append. ++ * @text_length: the length of the @text, or -1 if it is %NULL terminated. ++ * @item_offset: the offset of the first code point to add to the @buffer. ++ * @item_length: the number of code points to add to the @buffer, or -1 for the ++ * end of @text (assuming it is %NULL terminated). ++ * ++ * Appends characters from @text array to @buffer. The @item_offset is the ++ * position of the first character from @text that will be appended, and ++ * @item_length is the number of character. When shaping part of a larger text ++ * (e.g. a run of text from a paragraph), instead of passing just the substring ++ * corresponding to the run, it is preferable to pass the whole ++ * paragraph and specify the run start and length as @item_offset and ++ * @item_length, respectively, to give HarfBuzz the full context to be able, ++ * for example, to do cross-run Arabic shaping or properly handle combining ++ * marks at stat of run. + * +- * ++ * This function does not check the validity of @text, it is up to the caller ++ * to ensure it contains a valid Unicode code points. + * +- * Since: 1.0 ++ * Since: 0.9.31 + **/ + void + hb_buffer_add_codepoints (hb_buffer_t *buffer, +@@ -1482,7 +1720,7 @@ + unsigned int item_offset, + int item_length) + { +- hb_buffer_add_utf (buffer, text, text_length, item_offset, item_length); ++ hb_buffer_add_utf > (buffer, text, text_length, item_offset, item_length); + } + + +@@ -1528,7 +1766,7 @@ + pos[end - 1].x_advance = total_x_advance; + pos[end - 1].y_advance = total_y_advance; + +- hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); ++ hb_stable_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start); + } else { + /* Transfer all cluster advance to the first glyph. */ + pos[start].x_advance += total_x_advance; +@@ -1537,17 +1775,20 @@ + pos[i].x_offset -= total_x_advance; + pos[i].y_offset -= total_y_advance; + } +- hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); ++ hb_stable_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1); + } + } + + /** + * hb_buffer_normalize_glyphs: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t. + * +- * ++ * Reorders a glyph buffer to have canonical in-cluster glyph order / position. ++ * The resulting clusters should behave identical to pre-reordering clusters. + * +- * Since: 1.0 ++ * This has nothing to do with Unicode normalization. ++ * ++ * Since: 0.9.2 + **/ + void + hb_buffer_normalize_glyphs (hb_buffer_t *buffer) +@@ -1570,3 +1811,66 @@ + } + normalize_glyphs_cluster (buffer, start, end, backward); + } ++ ++void ++hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)) ++{ ++ assert (!have_positions); ++ for (unsigned int i = start + 1; i < end; i++) ++ { ++ unsigned int j = i; ++ while (j > start && compar (&info[j - 1], &info[i]) > 0) ++ j--; ++ if (i == j) ++ continue; ++ /* Move item i to occupy place for item j, shift what's in between. */ ++ merge_clusters (j, i + 1); ++ { ++ hb_glyph_info_t t = info[i]; ++ memmove (&info[j + 1], &info[j], (i - j) * sizeof (hb_glyph_info_t)); ++ info[j] = t; ++ } ++ } ++} ++ ++/* ++ * Debugging. ++ */ ++ ++/** ++ * hb_buffer_set_message_func: ++ * @buffer: an #hb_buffer_t. ++ * @func: (closure user_data) (destroy destroy) (scope notified): ++ * @user_data: ++ * @destroy: ++ * ++ * ++ * ++ * Since: 1.1.3 ++ **/ ++void ++hb_buffer_set_message_func (hb_buffer_t *buffer, ++ hb_buffer_message_func_t func, ++ void *user_data, hb_destroy_func_t destroy) ++{ ++ if (buffer->message_destroy) ++ buffer->message_destroy (buffer->message_data); ++ ++ if (func) { ++ buffer->message_func = func; ++ buffer->message_data = user_data; ++ buffer->message_destroy = destroy; ++ } else { ++ buffer->message_func = NULL; ++ buffer->message_data = NULL; ++ buffer->message_destroy = NULL; ++ } ++} ++ ++bool ++hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) ++{ ++ char buf[100]; ++ vsnprintf (buf, sizeof (buf), fmt, ap); ++ return (bool) this->message_func (this, font, buf, this->message_data); ++} +diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-json.hh gfx/harfbuzz/src/hb-buffer-deserialize-json.hh +--- gfx/harfbuzz/src_old/hb-buffer-deserialize-json.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer-deserialize-json.hh 2016-06-05 23:48:20.553345078 +0200 +@@ -1,5 +1,5 @@ + +-#line 1 "../../src/hb-buffer-deserialize-json.rl" ++#line 1 "hb-buffer-deserialize-json.rl" + /* + * Copyright © 2013 Google, Inc. + * +@@ -32,7 +32,7 @@ + #include "hb-private.hh" + + +-#line 36 "hb-buffer-deserialize-json.hh.tmp" ++#line 36 "hb-buffer-deserialize-json.hh" + static const unsigned char _deserialize_json_trans_keys[] = { + 0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, +@@ -435,7 +435,7 @@ + static const int deserialize_json_en_main = 1; + + +-#line 97 "../../src/hb-buffer-deserialize-json.rl" ++#line 97 "hb-buffer-deserialize-json.rl" + + + static hb_bool_t +@@ -459,15 +459,15 @@ + + const char *tok = NULL; + int cs; +- hb_glyph_info_t info; +- hb_glyph_position_t pos; ++ hb_glyph_info_t info = {0}; ++ hb_glyph_position_t pos = {0}; + +-#line 466 "hb-buffer-deserialize-json.hh.tmp" ++#line 466 "hb-buffer-deserialize-json.hh" + { + cs = deserialize_json_start; + } + +-#line 471 "hb-buffer-deserialize-json.hh.tmp" ++#line 471 "hb-buffer-deserialize-json.hh" + { + int _slen; + int _trans; +@@ -493,14 +493,14 @@ + + switch ( _deserialize_json_trans_actions[_trans] ) { + case 1: +-#line 38 "../../src/hb-buffer-deserialize-json.rl" ++#line 38 "hb-buffer-deserialize-json.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + break; + case 5: +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -510,13 +510,13 @@ + } + break; + case 2: +-#line 51 "../../src/hb-buffer-deserialize-json.rl" ++#line 51 "hb-buffer-deserialize-json.rl" + { + tok = p; + } + break; + case 14: +-#line 55 "../../src/hb-buffer-deserialize-json.rl" ++#line 55 "hb-buffer-deserialize-json.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, +@@ -525,33 +525,33 @@ + } + break; + case 15: +-#line 62 "../../src/hb-buffer-deserialize-json.rl" ++#line 62 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } + break; + case 8: +-#line 63 "../../src/hb-buffer-deserialize-json.rl" ++#line 63 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 10: +-#line 64 "../../src/hb-buffer-deserialize-json.rl" ++#line 64 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +-#line 65 "../../src/hb-buffer-deserialize-json.rl" ++#line 65 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 3: +-#line 66 "../../src/hb-buffer-deserialize-json.rl" ++#line 66 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 6: +-#line 67 "../../src/hb-buffer-deserialize-json.rl" ++#line 67 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 16: +-#line 62 "../../src/hb-buffer-deserialize-json.rl" ++#line 62 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -561,9 +561,9 @@ + } + break; + case 9: +-#line 63 "../../src/hb-buffer-deserialize-json.rl" ++#line 63 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -573,9 +573,9 @@ + } + break; + case 11: +-#line 64 "../../src/hb-buffer-deserialize-json.rl" ++#line 64 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -585,9 +585,9 @@ + } + break; + case 13: +-#line 65 "../../src/hb-buffer-deserialize-json.rl" ++#line 65 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -597,9 +597,9 @@ + } + break; + case 4: +-#line 66 "../../src/hb-buffer-deserialize-json.rl" ++#line 66 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -609,9 +609,9 @@ + } + break; + case 7: +-#line 67 "../../src/hb-buffer-deserialize-json.rl" ++#line 67 "hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-json.rl" ++#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -620,7 +620,7 @@ + *end_ptr = p; + } + break; +-#line 624 "hb-buffer-deserialize-json.hh.tmp" ++#line 624 "hb-buffer-deserialize-json.hh" + } + + _again: +@@ -632,7 +632,7 @@ + _out: {} + } + +-#line 125 "../../src/hb-buffer-deserialize-json.rl" ++#line 125 "hb-buffer-deserialize-json.rl" + + + *end_ptr = p; +diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-text.hh gfx/harfbuzz/src/hb-buffer-deserialize-text.hh +--- gfx/harfbuzz/src_old/hb-buffer-deserialize-text.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer-deserialize-text.hh 2016-06-05 23:48:23.120330665 +0200 +@@ -1,5 +1,5 @@ + +-#line 1 "../../src/hb-buffer-deserialize-text.rl" ++#line 1 "hb-buffer-deserialize-text.rl" + /* + * Copyright © 2013 Google, Inc. + * +@@ -32,7 +32,7 @@ + #include "hb-private.hh" + + +-#line 36 "hb-buffer-deserialize-text.hh.tmp" ++#line 36 "hb-buffer-deserialize-text.hh" + static const unsigned char _deserialize_text_trans_keys[] = { + 0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, +@@ -312,7 +312,7 @@ + static const int deserialize_text_en_main = 1; + + +-#line 91 "../../src/hb-buffer-deserialize-text.rl" ++#line 91 "hb-buffer-deserialize-text.rl" + + + static hb_bool_t +@@ -336,15 +336,15 @@ + + const char *eof = pe, *tok = NULL; + int cs; +- hb_glyph_info_t info; +- hb_glyph_position_t pos; ++ hb_glyph_info_t info = {0}; ++ hb_glyph_position_t pos = {0}; + +-#line 343 "hb-buffer-deserialize-text.hh.tmp" ++#line 343 "hb-buffer-deserialize-text.hh" + { + cs = deserialize_text_start; + } + +-#line 348 "hb-buffer-deserialize-text.hh.tmp" ++#line 348 "hb-buffer-deserialize-text.hh" + { + int _slen; + int _trans; +@@ -370,13 +370,13 @@ + + switch ( _deserialize_text_trans_actions[_trans] ) { + case 2: +-#line 51 "../../src/hb-buffer-deserialize-text.rl" ++#line 51 "hb-buffer-deserialize-text.rl" + { + tok = p; + } + break; + case 5: +-#line 55 "../../src/hb-buffer-deserialize-text.rl" ++#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, +@@ -385,41 +385,41 @@ + } + break; + case 10: +-#line 62 "../../src/hb-buffer-deserialize-text.rl" ++#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 3: +-#line 63 "../../src/hb-buffer-deserialize-text.rl" ++#line 63 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +-#line 64 "../../src/hb-buffer-deserialize-text.rl" ++#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 7: +-#line 65 "../../src/hb-buffer-deserialize-text.rl" ++#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 1: +-#line 38 "../../src/hb-buffer-deserialize-text.rl" ++#line 38 "hb-buffer-deserialize-text.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } +-#line 51 "../../src/hb-buffer-deserialize-text.rl" ++#line 51 "hb-buffer-deserialize-text.rl" + { + tok = p; + } + break; + case 4: +-#line 55 "../../src/hb-buffer-deserialize-text.rl" ++#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -429,9 +429,9 @@ + } + break; + case 9: +-#line 62 "../../src/hb-buffer-deserialize-text.rl" ++#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -441,9 +441,9 @@ + } + break; + case 11: +-#line 64 "../../src/hb-buffer-deserialize-text.rl" ++#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -453,9 +453,9 @@ + } + break; + case 6: +-#line 65 "../../src/hb-buffer-deserialize-text.rl" ++#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -465,9 +465,9 @@ + } + break; + case 8: +-#line 66 "../../src/hb-buffer-deserialize-text.rl" ++#line 66 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -476,7 +476,7 @@ + *end_ptr = p; + } + break; +-#line 480 "hb-buffer-deserialize-text.hh.tmp" ++#line 480 "hb-buffer-deserialize-text.hh" + } + + _again: +@@ -489,14 +489,14 @@ + { + switch ( _deserialize_text_eof_actions[cs] ) { + case 4: +-#line 55 "../../src/hb-buffer-deserialize-text.rl" ++#line 55 "hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -506,9 +506,9 @@ + } + break; + case 9: +-#line 62 "../../src/hb-buffer-deserialize-text.rl" ++#line 62 "hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -518,9 +518,9 @@ + } + break; + case 11: +-#line 64 "../../src/hb-buffer-deserialize-text.rl" ++#line 64 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -530,9 +530,9 @@ + } + break; + case 6: +-#line 65 "../../src/hb-buffer-deserialize-text.rl" ++#line 65 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -542,9 +542,9 @@ + } + break; + case 8: +-#line 66 "../../src/hb-buffer-deserialize-text.rl" ++#line 66 "hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +-#line 43 "../../src/hb-buffer-deserialize-text.rl" ++#line 43 "hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) +@@ -553,14 +553,14 @@ + *end_ptr = p; + } + break; +-#line 557 "hb-buffer-deserialize-text.hh.tmp" ++#line 557 "hb-buffer-deserialize-text.hh" + } + } + + _out: {} + } + +-#line 119 "../../src/hb-buffer-deserialize-text.rl" ++#line 119 "hb-buffer-deserialize-text.rl" + + + *end_ptr = p; +diff -uN gfx/harfbuzz/src_old/hb-buffer-deserialize-text.rl gfx/harfbuzz/src/hb-buffer-deserialize-text.rl +--- gfx/harfbuzz/src_old/hb-buffer-deserialize-text.rl 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer-deserialize-text.rl 2016-06-05 23:48:24.307324017 +0200 +@@ -111,8 +111,8 @@ + + const char *eof = pe, *tok = NULL; + int cs; +- hb_glyph_info_t info; +- hb_glyph_position_t pos; ++ hb_glyph_info_t info = {0}; ++ hb_glyph_position_t pos = {0}; + %%{ + write init; + write exec; +diff -uN gfx/harfbuzz/src_old/hb-buffer.h gfx/harfbuzz/src/hb-buffer.h +--- gfx/harfbuzz/src_old/hb-buffer.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer.h 2016-06-05 23:48:29.670294025 +0200 +@@ -40,7 +40,27 @@ + + HB_BEGIN_DECLS + +- ++/** ++ * hb_glyph_info_t: ++ * @codepoint: either a Unicode code point (before shaping) or a glyph index ++ * (after shaping). ++ * @mask: ++ * @cluster: the index of the character in the original text that corresponds ++ * to this #hb_glyph_info_t, or whatever the client passes to ++ * hb_buffer_add(). More than one #hb_glyph_info_t can have the same ++ * @cluster value, if they resulted from the same character (e.g. one ++ * to many glyph substitution), and when more than one character gets ++ * merged in the same glyph (e.g. many to one glyph substitution) the ++ * #hb_glyph_info_t will have the smallest cluster value of them. ++ * By default some characters are merged into the same cluster ++ * (e.g. combining marks have the same cluster as their bases) ++ * even if they are separate glyphs, hb_buffer_set_cluster_level() ++ * allow selecting more fine-grained cluster handling. ++ * ++ * The #hb_glyph_info_t is the structure that holds information about the ++ * glyphs and their relation to input text. ++ * ++ */ + typedef struct hb_glyph_info_t { + hb_codepoint_t codepoint; + hb_mask_t mask; +@@ -51,6 +71,22 @@ + hb_var_int_t var2; + } hb_glyph_info_t; + ++/** ++ * hb_glyph_position_t: ++ * @x_advance: how much the line advances after drawing this glyph when setting ++ * text in horizontal direction. ++ * @y_advance: how much the line advances after drawing this glyph when setting ++ * text in vertical direction. ++ * @x_offset: how much the glyph moves on the X-axis before drawing it, this ++ * should not affect how much the line advances. ++ * @y_offset: how much the glyph moves on the Y-axis before drawing it, this ++ * should not affect how much the line advances. ++ * ++ * The #hb_glyph_position_t is the structure that holds the positions of the ++ * glyph in both horizontal and vertical directions. All positions in ++ * #hb_glyph_position_t are relative to the current point. ++ * ++ */ + typedef struct hb_glyph_position_t { + hb_position_t x_advance; + hb_position_t y_advance; +@@ -61,7 +97,16 @@ + hb_var_int_t var; + } hb_glyph_position_t; + +- ++/** ++ * hb_segment_properties_t: ++ * @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction(). ++ * @script: the #hb_script_t of the buffer, see hb_buffer_set_script(). ++ * @language: the #hb_language_t of the buffer, see hb_buffer_set_language(). ++ * ++ * The structure that holds various text properties of an #hb_buffer_t. Can be ++ * set and retrieved using hb_buffer_set_segment_properties() and ++ * hb_buffer_get_segment_properties(), respectively. ++ */ + typedef struct hb_segment_properties_t { + hb_direction_t direction; + hb_script_t script; +@@ -77,100 +122,127 @@ + NULL, \ + NULL} + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b); + +-unsigned int ++HB_EXTERN unsigned int + hb_segment_properties_hash (const hb_segment_properties_t *p); + + + +-/* +- * hb_buffer_t ++/** ++ * hb_buffer_t: ++ * ++ * The main structure holding the input text and its properties before shaping, ++ * and output glyphs and their information after shaping. + */ + + typedef struct hb_buffer_t hb_buffer_t; + +-hb_buffer_t * ++HB_EXTERN hb_buffer_t * + hb_buffer_create (void); + +-hb_buffer_t * ++HB_EXTERN hb_buffer_t * + hb_buffer_get_empty (void); + +-hb_buffer_t * ++HB_EXTERN hb_buffer_t * + hb_buffer_reference (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_destroy (hb_buffer_t *buffer); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_buffer_set_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +-void * ++HB_EXTERN void * + hb_buffer_get_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key); + +- ++/** ++ * hb_buffer_content_type_t: ++ * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer. ++ * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping). ++ * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping). ++ */ + typedef enum { + HB_BUFFER_CONTENT_TYPE_INVALID = 0, + HB_BUFFER_CONTENT_TYPE_UNICODE, + HB_BUFFER_CONTENT_TYPE_GLYPHS + } hb_buffer_content_type_t; + +-void ++HB_EXTERN void + hb_buffer_set_content_type (hb_buffer_t *buffer, + hb_buffer_content_type_t content_type); + +-hb_buffer_content_type_t ++HB_EXTERN hb_buffer_content_type_t + hb_buffer_get_content_type (hb_buffer_t *buffer); + + +-void ++HB_EXTERN void + hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, + hb_unicode_funcs_t *unicode_funcs); + +-hb_unicode_funcs_t * ++HB_EXTERN hb_unicode_funcs_t * + hb_buffer_get_unicode_funcs (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_set_direction (hb_buffer_t *buffer, + hb_direction_t direction); + +-hb_direction_t ++HB_EXTERN hb_direction_t + hb_buffer_get_direction (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_set_script (hb_buffer_t *buffer, + hb_script_t script); + +-hb_script_t ++HB_EXTERN hb_script_t + hb_buffer_get_script (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_set_language (hb_buffer_t *buffer, + hb_language_t language); + + +-hb_language_t ++HB_EXTERN hb_language_t + hb_buffer_get_language (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_set_segment_properties (hb_buffer_t *buffer, + const hb_segment_properties_t *props); + +-void ++HB_EXTERN void + hb_buffer_get_segment_properties (hb_buffer_t *buffer, + hb_segment_properties_t *props); + +-void ++HB_EXTERN void + hb_buffer_guess_segment_properties (hb_buffer_t *buffer); + + ++/** ++ * hb_buffer_flags_t: ++ * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag. ++ * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning ++ * of text paragraph can be applied to this buffer. Should usually ++ * be set, unless you are passing to the buffer only part ++ * of the text without the full context. ++ * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text ++ * paragraph can be applied to this buffer, similar to ++ * @HB_BUFFER_FLAG_EOT. ++ * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES: ++ * flag indication that character with Default_Ignorable ++ * Unicode property should use the corresponding glyph ++ * from the font, instead of hiding them (currently done ++ * by replacing them with the space glyph and zeroing the ++ * advance width.) ++ * ++ * Since: 0.9.20 ++ */ + typedef enum { /*< flags >*/ + HB_BUFFER_FLAG_DEFAULT = 0x00000000u, + HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */ +@@ -178,83 +250,109 @@ + HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u + } hb_buffer_flags_t; + +-void ++HB_EXTERN void + hb_buffer_set_flags (hb_buffer_t *buffer, + hb_buffer_flags_t flags); + +-hb_buffer_flags_t ++HB_EXTERN hb_buffer_flags_t + hb_buffer_get_flags (hb_buffer_t *buffer); + +- +- ++/* ++ * Since: 0.9.42 ++ */ ++typedef enum { ++ HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0, ++ HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1, ++ HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2, ++ HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES ++} hb_buffer_cluster_level_t; ++ ++HB_EXTERN void ++hb_buffer_set_cluster_level (hb_buffer_t *buffer, ++ hb_buffer_cluster_level_t cluster_level); ++ ++HB_EXTERN hb_buffer_cluster_level_t ++hb_buffer_get_cluster_level (hb_buffer_t *buffer); ++ ++/** ++ * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT: ++ * ++ * The default code point for replacing invalid characters in a given encoding. ++ * Set to U+FFFD REPLACEMENT CHARACTER. ++ * ++ * Since: 0.9.31 ++ */ + #define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu + +-/* Sets codepoint used to replace invalid UTF-8/16/32 entries. +- * Default is 0xFFFDu. */ +-void ++HB_EXTERN void + hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, + hb_codepoint_t replacement); + +-hb_codepoint_t ++HB_EXTERN hb_codepoint_t + hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer); + + +-/* Resets the buffer. Afterwards it's as if it was just created, +- * except that it has a larger buffer allocated perhaps... */ +-void ++HB_EXTERN void + hb_buffer_reset (hb_buffer_t *buffer); + +-/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */ +-void ++HB_EXTERN void + hb_buffer_clear_contents (hb_buffer_t *buffer); + +-/* Returns false if allocation failed */ +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_buffer_pre_allocate (hb_buffer_t *buffer, + unsigned int size); + + +-/* Returns false if allocation has failed before */ +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_buffer_allocation_successful (hb_buffer_t *buffer); + +-void ++HB_EXTERN void + hb_buffer_reverse (hb_buffer_t *buffer); + +-void ++HB_EXTERN void ++hb_buffer_reverse_range (hb_buffer_t *buffer, ++ unsigned int start, unsigned int end); ++ ++HB_EXTERN void + hb_buffer_reverse_clusters (hb_buffer_t *buffer); + + + /* Filling the buffer in */ + +-void ++HB_EXTERN void + hb_buffer_add (hb_buffer_t *buffer, + hb_codepoint_t codepoint, + unsigned int cluster); + +-void ++HB_EXTERN void + hb_buffer_add_utf8 (hb_buffer_t *buffer, + const char *text, + int text_length, + unsigned int item_offset, + int item_length); + +-void ++HB_EXTERN void + hb_buffer_add_utf16 (hb_buffer_t *buffer, + const uint16_t *text, + int text_length, + unsigned int item_offset, + int item_length); + +-void ++HB_EXTERN void + hb_buffer_add_utf32 (hb_buffer_t *buffer, + const uint32_t *text, + int text_length, + unsigned int item_offset, + int item_length); + +-/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */ +-void ++HB_EXTERN void ++hb_buffer_add_latin1 (hb_buffer_t *buffer, ++ const uint8_t *text, ++ int text_length, ++ unsigned int item_offset, ++ int item_length); ++ ++HB_EXTERN void + hb_buffer_add_codepoints (hb_buffer_t *buffer, + const hb_codepoint_t *text, + int text_length, +@@ -262,32 +360,25 @@ + int item_length); + + +-/* Clears any new items added at the end */ +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_buffer_set_length (hb_buffer_t *buffer, + unsigned int length); + +-/* Return value valid as long as buffer not modified */ +-unsigned int ++HB_EXTERN unsigned int + hb_buffer_get_length (hb_buffer_t *buffer); + + /* Getting glyphs out of the buffer */ + +-/* Return value valid as long as buffer not modified */ +-hb_glyph_info_t * ++HB_EXTERN hb_glyph_info_t * + hb_buffer_get_glyph_infos (hb_buffer_t *buffer, + unsigned int *length); + +-/* Return value valid as long as buffer not modified */ +-hb_glyph_position_t * ++HB_EXTERN hb_glyph_position_t * + hb_buffer_get_glyph_positions (hb_buffer_t *buffer, + unsigned int *length); + + +-/* Reorders a glyph buffer to have canonical in-cluster glyph order / position. +- * The resulting clusters should behave identical to pre-reordering clusters. +- * NOTE: This has nothing to do with Unicode normalization. */ +-void ++HB_EXTERN void + hb_buffer_normalize_glyphs (hb_buffer_t *buffer); + + +@@ -295,50 +386,87 @@ + * Serialize + */ + ++/** ++ * hb_buffer_serialize_flags_t: ++ * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions. ++ * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster. ++ * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information. ++ * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name. ++ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents. ++ * ++ * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs(). ++ * ++ * Since: 0.9.20 ++ */ + typedef enum { /*< flags >*/ + HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u, + HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u, + HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u, +- HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u ++ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u, ++ HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u + } hb_buffer_serialize_flags_t; + ++/** ++ * hb_buffer_serialize_format_t: ++ * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format. ++ * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format. ++ * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format. ++ * ++ * The buffer serialization and de-serialization format used in ++ * hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs(). ++ * ++ * Since: 0.9.2 ++ */ + typedef enum { + HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'), + HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'), + HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE + } hb_buffer_serialize_format_t; + +-/* len=-1 means str is NUL-terminated. */ +-hb_buffer_serialize_format_t ++HB_EXTERN hb_buffer_serialize_format_t + hb_buffer_serialize_format_from_string (const char *str, int len); + +-const char * ++HB_EXTERN const char * + hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format); + +-const char ** ++HB_EXTERN const char ** + hb_buffer_serialize_list_formats (void); + +-/* Returns number of items, starting at start, that were serialized. */ +-unsigned int ++HB_EXTERN unsigned int + hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, +- unsigned int *buf_consumed, /* May be NULL */ +- hb_font_t *font, /* May be NULL */ ++ unsigned int *buf_consumed, ++ hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, +- int buf_len, /* -1 means nul-terminated */ +- const char **end_ptr, /* May be NULL */ +- hb_font_t *font, /* May be NULL */ ++ int buf_len, ++ const char **end_ptr, ++ hb_font_t *font, + hb_buffer_serialize_format_t format); + + ++/* ++ * Debugging. ++ */ ++ ++typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer, ++ hb_font_t *font, ++ const char *message, ++ void *user_data); ++ ++HB_EXTERN void ++hb_buffer_set_message_func (hb_buffer_t *buffer, ++ hb_buffer_message_func_t func, ++ void *user_data, hb_destroy_func_t destroy); ++ ++ + HB_END_DECLS + + #endif /* HB_BUFFER_H */ +diff -uN gfx/harfbuzz/src_old/hb-buffer-private.hh gfx/harfbuzz/src/hb-buffer-private.hh +--- gfx/harfbuzz/src_old/hb-buffer-private.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer-private.hh 2016-06-05 23:48:25.604316742 +0200 +@@ -35,9 +35,37 @@ + #include "hb-unicode-private.hh" + + ++#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR ++#define HB_BUFFER_MAX_EXPANSION_FACTOR 32 ++#endif ++#ifndef HB_BUFFER_MAX_LEN_MIN ++#define HB_BUFFER_MAX_LEN_MIN 8192 ++#endif ++#ifndef HB_BUFFER_MAX_LEN_DEFAULT ++#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ ++#endif ++ + ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); + ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); + ++HB_MARK_AS_FLAG_T (hb_buffer_flags_t); ++HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t); ++ ++enum hb_buffer_scratch_flags_t { ++ HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u, ++ HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u, ++ HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u, ++ HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u, ++ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE = 0x00000008u, ++ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000010u, ++ /* Reserved for complex shapers' internal use. */ ++ HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u, ++ HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u, ++ HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u, ++ HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u, ++}; ++HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t); ++ + + /* + * hb_buffer_t +@@ -50,7 +78,10 @@ + /* Information about how the text in the buffer should be treated */ + hb_unicode_funcs_t *unicode; /* Unicode functions */ + hb_buffer_flags_t flags; /* BOT / EOT / etc. */ ++ hb_buffer_cluster_level_t cluster_level; + hb_codepoint_t replacement; /* U+FFFD or something else. */ ++ hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */ ++ unsigned int max_len; /* Maximum allowed len. */ + + /* Buffer contents */ + hb_buffer_content_type_t content_type; +@@ -75,8 +106,8 @@ + inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } + inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } + +- inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; } +- inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; } ++ inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; } ++ inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; } + + inline bool has_separate_output (void) const { return info != out_info; } + +@@ -93,6 +124,11 @@ + hb_codepoint_t context[2][CONTEXT_LENGTH]; + unsigned int context_len[2]; + ++ /* Debugging */ ++ hb_buffer_message_func_t message_func; ++ void *message_data; ++ hb_destroy_func_t message_destroy; ++ + + /* Methods */ + +@@ -171,9 +207,18 @@ + unsigned int cluster_end); + + HB_INTERNAL void merge_clusters (unsigned int start, +- unsigned int end); ++ unsigned int end) ++ { ++ if (end - start < 2) ++ return; ++ merge_clusters_impl (start, end); ++ } ++ HB_INTERNAL void merge_clusters_impl (unsigned int start, ++ unsigned int end); + HB_INTERNAL void merge_out_clusters (unsigned int start, + unsigned int end); ++ /* Merge clusters for deleting current glyph, and skip it. */ ++ HB_INTERNAL void delete_glyph (void); + + /* Internal methods */ + HB_INTERNAL bool enlarge (unsigned int size); +@@ -191,6 +236,21 @@ + HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size); + + inline void clear_context (unsigned int side) { context_len[side] = 0; } ++ ++ HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)); ++ ++ inline bool messaging (void) { return unlikely (message_func); } ++ inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) ++ { ++ if (!messaging ()) ++ return true; ++ va_list ap; ++ va_start (ap, fmt); ++ bool ret = message_impl (font, fmt, ap); ++ va_end (ap); ++ return ret; ++ } ++ HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0); + }; + + +diff -uN gfx/harfbuzz/src_old/hb-buffer-serialize.cc gfx/harfbuzz/src/hb-buffer-serialize.cc +--- gfx/harfbuzz/src_old/hb-buffer-serialize.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-buffer-serialize.cc 2016-06-05 23:48:26.782310166 +0200 +@@ -36,11 +36,12 @@ + /** + * hb_buffer_serialize_list_formats: + * +- * ++ * Returns a list of supported buffer serialization formats. + * + * Return value: (transfer none): ++ * A string array of buffer serialization formats. Should not be freed. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + const char ** + hb_buffer_serialize_list_formats (void) +@@ -50,14 +51,17 @@ + + /** + * hb_buffer_serialize_format_from_string: +- * @str: +- * @len: ++ * @str: (array length=len) (element-type uint8_t): a string to parse ++ * @len: length of @str, or -1 if string is %NULL terminated + * +- * ++ * Parses a string into an #hb_buffer_serialize_format_t. Does not check if ++ * @str is a valid buffer serialization format, use ++ * hb_buffer_serialize_list_formats() to get the list of supported formats. + * + * Return value: ++ * The parsed #hb_buffer_serialize_format_t. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + hb_buffer_serialize_format_t + hb_buffer_serialize_format_from_string (const char *str, int len) +@@ -68,13 +72,15 @@ + + /** + * hb_buffer_serialize_format_to_string: +- * @format: ++ * @format: an #hb_buffer_serialize_format_t to convert. + * +- * ++ * Converts @format to the string corresponding it, or %NULL if it is not a valid ++ * #hb_buffer_serialize_format_t. + * +- * Return value: ++ * Return value: (transfer none): ++ * A %NULL terminated string corresponding to @format. Should not be freed. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + const char * + hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) +@@ -99,7 +105,8 @@ + hb_buffer_serialize_flags_t flags) + { + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); +- hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); ++ hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? ++ NULL : hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) +@@ -144,6 +151,16 @@ + pos[i].x_advance, pos[i].y_advance); + } + ++ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) ++ { ++ hb_glyph_extents_t extents; ++ hb_font_get_glyph_extents(font, info[i].codepoint, &extents); ++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", ++ extents.x_bearing, extents.y_bearing)); ++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", ++ extents.width, extents.height)); ++ } ++ + *p++ = '}'; + + unsigned int l = p - b; +@@ -172,7 +189,8 @@ + hb_buffer_serialize_flags_t flags) + { + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); +- hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); ++ hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? ++ NULL : hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) +@@ -208,6 +226,13 @@ + p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); + } + ++ if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) ++ { ++ hb_glyph_extents_t extents; ++ hb_font_get_glyph_extents(font, info[i].codepoint, &extents); ++ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); ++ } ++ + unsigned int l = p - b; + if (buf_size > l) + { +@@ -223,24 +248,51 @@ + return end - start; + } + +-/* Returns number of items, starting at start, that were serialized. */ + /** + * hb_buffer_serialize_glyphs: +- * @buffer: a buffer. +- * @start: +- * @end: +- * @buf: (array length=buf_size): +- * @buf_size: +- * @buf_consumed: (out): +- * @font: +- * @format: +- * @flags: ++ * @buffer: an #hb_buffer_t buffer. ++ * @start: the first item in @buffer to serialize. ++ * @end: the last item in @buffer to serialize. ++ * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to ++ * write serialized buffer into. ++ * @buf_size: the size of @buf. ++ * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf. ++ * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to ++ * read glyph names and extents. If %NULL, and empty font will be used. ++ * @format: the #hb_buffer_serialize_format_t to use for formatting the output. ++ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties ++ * to serialize. ++ * ++ * Serializes @buffer into a textual representation of its glyph content, ++ * useful for showing the contents of the buffer, for example during debugging. ++ * There are currently two supported serialization formats: ++ * ++ * ## text ++ * A human-readable, plain text format. ++ * The serialized glyphs will look something like: ++ * ++ * ``` ++ * [uni0651=0@518,0+0|uni0628=0+1897] ++ * ``` ++ * - The serialized glyphs are delimited with `[` and `]`. ++ * - Glyphs are separated with `|` ++ * - Each glyph starts with glyph name, or glyph index if ++ * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then, ++ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster. ++ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format: ++ * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then, ++ * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then, ++ * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the ++ * #hb_glyph_extents_t in the format ++ * `<x_bearing,y_bearing,width,height>` + * +- * ++ * ## json ++ * TODO. + * + * Return value: ++ * The number of serialized items. + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + unsigned int + hb_buffer_serialize_glyphs (hb_buffer_t *buffer, +@@ -248,8 +300,8 @@ + unsigned int end, + char *buf, + unsigned int buf_size, +- unsigned int *buf_consumed, /* May be NULL */ +- hb_font_t *font, /* May be NULL */ ++ unsigned int *buf_consumed, ++ hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) + { +@@ -263,6 +315,9 @@ + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + ++ if (!buffer->have_positions) ++ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS; ++ + if (unlikely (start == end)) + return 0; + +@@ -336,7 +391,7 @@ + + /** + * hb_buffer_deserialize_glyphs: +- * @buffer: a buffer. ++ * @buffer: an #hb_buffer_t buffer. + * @buf: (array length=buf_len): + * @buf_len: + * @end_ptr: (out): +@@ -347,7 +402,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + hb_bool_t + hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, +diff -uN gfx/harfbuzz/src_old/hb-common.cc gfx/harfbuzz/src/hb-common.cc +--- gfx/harfbuzz/src_old/hb-common.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-common.cc 2016-06-05 23:48:32.151280204 +0200 +@@ -57,14 +57,14 @@ + + /** + * hb_tag_from_string: +- * @str: (array length=len): ++ * @str: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_tag_t + hb_tag_from_string (const char *str, int len) +@@ -92,7 +92,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.5 + **/ + void + hb_tag_to_string (hb_tag_t tag, char *buf) +@@ -115,14 +115,14 @@ + + /** + * hb_direction_from_string: +- * @str: (array length=len): ++ * @str: (array length=len) (element-type uint8_t): + * @len: + * + * + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_direction_t + hb_direction_from_string (const char *str, int len) +@@ -149,7 +149,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + const char * + hb_direction_to_string (hb_direction_t direction) +@@ -179,7 +179,7 @@ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 + }; + +-static hb_bool_t ++static bool + lang_equal (hb_language_t v1, + const void *v2) + { +@@ -235,7 +235,7 @@ + static hb_language_item_t *langs; + + #ifdef HB_USE_ATEXIT +-static inline ++static + void free_langs (void) + { + while (langs) { +@@ -265,6 +265,7 @@ + *lang = key; + + if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { ++ lang->finish (); + free (lang); + goto retry; + } +@@ -280,46 +281,51 @@ + + /** + * hb_language_from_string: +- * @str: (array length=len): +- * @len: ++ * @str: (array length=len) (element-type uint8_t): a string representing ++ * ISO 639 language code ++ * @len: length of the @str, or -1 if it is %NULL-terminated. + * +- * ++ * Converts @str representing an ISO 639 language code to the corresponding ++ * #hb_language_t. + * +- * Return value: ++ * Return value: (transfer none): ++ * The #hb_language_t corresponding to the ISO 639 language code. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_language_t + hb_language_from_string (const char *str, int len) + { +- char strbuf[64]; +- + if (!str || !len || !*str) + return HB_LANGUAGE_INVALID; + ++ hb_language_item_t *item = NULL; + if (len >= 0) + { + /* NUL-terminate it. */ ++ char strbuf[64]; + len = MIN (len, (int) sizeof (strbuf) - 1); + memcpy (strbuf, str, len); + strbuf[len] = '\0'; +- str = strbuf; ++ item = lang_find_or_insert (strbuf); + } +- +- hb_language_item_t *item = lang_find_or_insert (str); ++ else ++ item = lang_find_or_insert (str); + + return likely (item) ? item->lang : HB_LANGUAGE_INVALID; + } + + /** + * hb_language_to_string: +- * @language: ++ * @language: an #hb_language_t to convert. + * +- * ++ * See hb_language_from_string(). + * +- * Return value: (transfer none): ++ * Return value: (transfer none): ++ * A %NULL-terminated string representing the @language. Must not be freed by ++ * the caller. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + const char * + hb_language_to_string (hb_language_t language) +@@ -333,9 +339,9 @@ + * + * + * +- * Return value: ++ * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_language_t + hb_language_get_default (void) +@@ -345,7 +351,7 @@ + hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); + if (unlikely (language == HB_LANGUAGE_INVALID)) { + language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1); +- hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); ++ (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); + } + + return default_language; +@@ -356,13 +362,14 @@ + + /** + * hb_script_from_iso15924_tag: +- * @tag: ++ * @tag: an #hb_tag_t representing an ISO 15924 tag. + * +- * ++ * Converts an ISO 15924 script tag to a corresponding #hb_script_t. + * + * Return value: ++ * An #hb_script_t corresponding to the ISO 15924 tag. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_script_t + hb_script_from_iso15924_tag (hb_tag_t tag) +@@ -400,30 +407,35 @@ + + /** + * hb_script_from_string: +- * @s: (array length=len): +- * @len: +- * +- * ++ * @str: (array length=len) (element-type uint8_t): a string representing an ++ * ISO 15924 tag. ++ * @len: length of the @str, or -1 if it is %NULL-terminated. ++ * ++ * Converts a string @str representing an ISO 15924 script tag to a ++ * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then ++ * hb_script_from_iso15924_tag(). + * + * Return value: ++ * An #hb_script_t corresponding to the ISO 15924 tag. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_script_t +-hb_script_from_string (const char *s, int len) ++hb_script_from_string (const char *str, int len) + { +- return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); ++ return hb_script_from_iso15924_tag (hb_tag_from_string (str, len)); + } + + /** + * hb_script_to_iso15924_tag: +- * @script: ++ * @script: an #hb_script_ to convert. + * +- * ++ * See hb_script_from_iso15924_tag(). + * +- * Return value: ++ * Return value: ++ * An #hb_tag_t representing an ISO 15924 script tag. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_tag_t + hb_script_to_iso15924_tag (hb_script_t script) +@@ -439,7 +451,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_direction_t + hb_script_get_horizontal_direction (hb_script_t script) +@@ -492,6 +504,9 @@ + case HB_SCRIPT_PALMYRENE: + case HB_SCRIPT_PSALTER_PAHLAVI: + ++ /* Unicode-8.0 additions */ ++ case HB_SCRIPT_OLD_HUNGARIAN: ++ + return HB_DIRECTION_RTL; + } + +@@ -517,7 +532,7 @@ + } + } + hb_user_data_item_t item = {key, data, destroy}; +- bool ret = !!items.replace_or_insert (item, lock, replace); ++ bool ret = !!items.replace_or_insert (item, lock, (bool) replace); + + return ret; + } +@@ -541,7 +556,7 @@ + * + * Returns library version as three integer components. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_version (unsigned int *major, +@@ -560,7 +575,7 @@ + * + * Return value: library version string. + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + const char * + hb_version_string (void) +@@ -578,7 +593,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.30 + **/ + hb_bool_t + hb_version_atleast (unsigned int major, +diff -uN gfx/harfbuzz/src_old/hb-common.h gfx/harfbuzz/src/hb-common.h +--- gfx/harfbuzz/src_old/hb-common.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-common.h 2016-06-05 23:48:33.399273253 +0200 +@@ -98,16 +98,22 @@ + #define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff) + + /* len=-1 means str is NUL-terminated. */ +-hb_tag_t ++HB_EXTERN hb_tag_t + hb_tag_from_string (const char *str, int len); + + /* buf should have 4 bytes. */ +-void ++HB_EXTERN void + hb_tag_to_string (hb_tag_t tag, char *buf); + + +-/* hb_direction_t */ +- ++/** ++ * hb_direction_t: ++ * @HB_DIRECTION_INVALID: Initial, unset direction. ++ * @HB_DIRECTION_LTR: Text is set horizontally from left to right. ++ * @HB_DIRECTION_RTL: Text is set horizontally from right to left. ++ * @HB_DIRECTION_TTB: Text is set vertically from top to bottom. ++ * @HB_DIRECTION_BTT: Text is set vertically from bottom to top. ++ */ + typedef enum { + HB_DIRECTION_INVALID = 0, + HB_DIRECTION_LTR = 4, +@@ -117,10 +123,10 @@ + } hb_direction_t; + + /* len=-1 means str is NUL-terminated */ +-hb_direction_t ++HB_EXTERN hb_direction_t + hb_direction_from_string (const char *str, int len); + +-const char * ++HB_EXTERN const char * + hb_direction_to_string (hb_direction_t direction); + + #define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4) +@@ -136,16 +142,15 @@ + + typedef const struct hb_language_impl_t *hb_language_t; + +-/* len=-1 means str is NUL-terminated */ +-hb_language_t ++HB_EXTERN hb_language_t + hb_language_from_string (const char *str, int len); + +-const char * ++HB_EXTERN const char * + hb_language_to_string (hb_language_t language); + + #define HB_LANGUAGE_INVALID ((hb_language_t) NULL) + +-hb_language_t ++HB_EXTERN hb_language_t + hb_language_get_default (void); + + +@@ -272,6 +277,9 @@ + /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), + /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), + ++ /* ++ * Since: 0.9.30 ++ */ + /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), + /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), + /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), +@@ -296,6 +304,13 @@ + /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), + /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), + ++ /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), ++ /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), ++ /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), ++ /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), ++ /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), ++ /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), ++ + /* No script set. */ + HB_SCRIPT_INVALID = HB_TAG_NONE, + +@@ -314,18 +329,16 @@ + + /* Script functions */ + +-hb_script_t ++HB_EXTERN hb_script_t + hb_script_from_iso15924_tag (hb_tag_t tag); + +-/* sugar for tag_from_string() then script_from_iso15924_tag */ +-/* len=-1 means s is NUL-terminated */ +-hb_script_t +-hb_script_from_string (const char *s, int len); ++HB_EXTERN hb_script_t ++hb_script_from_string (const char *str, int len); + +-hb_tag_t ++HB_EXTERN hb_tag_t + hb_script_to_iso15924_tag (hb_script_t script); + +-hb_direction_t ++HB_EXTERN hb_direction_t + hb_script_get_horizontal_direction (hb_script_t script); + + +diff -uN gfx/harfbuzz/src_old/hb-coretext.cc gfx/harfbuzz/src/hb-coretext.cc +--- gfx/harfbuzz/src_old/hb-coretext.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-coretext.cc 2016-06-05 23:48:34.938264688 +0200 +@@ -22,7 +22,7 @@ + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * +- * GNU Author(s): Jonathan Kew ++ * Mozilla Author(s): Jonathan Kew + * Google Author(s): Behdad Esfahbod + */ + +@@ -125,6 +125,9 @@ + CFRelease (data); + } + ++/* ++ * Since: 0.9.10 ++ */ + CGFontRef + hb_coretext_face_get_cg_font (hb_face_t *face) + { +@@ -140,6 +143,7 @@ + + struct hb_coretext_shaper_font_data_t { + CTFontRef ct_font; ++ CGFloat x_mult, y_mult; /* From CT space to HB space. */ + }; + + hb_coretext_shaper_font_data_t * +@@ -154,7 +158,55 @@ + hb_face_t *face = font->face; + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); + +- data->ct_font = CTFontCreateWithGraphicsFont (face_data, font->y_scale, NULL, NULL); ++ /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */ ++ /* TODO: use upem instead of 36? */ ++ CGFloat font_size = 36.; /* Default... */ ++ /* No idea if the following is even a good idea. */ ++ if (font->y_ppem) ++ font_size = font->y_ppem; ++ ++ if (font_size < 0) ++ font_size = -font_size; ++ data->x_mult = (CGFloat) font->x_scale / font_size; ++ data->y_mult = (CGFloat) font->y_scale / font_size; ++ data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL); ++ if (unlikely (!data->ct_font)) { ++ DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); ++ free (data); ++ return NULL; ++ } ++ ++ /* Create font copy with cascade list that has LastResort first; this speeds up CoreText ++ * font fallback which we don't need anyway. */ ++ { ++ // TODO Handle allocation failures? ++ CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0); ++ CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault, ++ (const void **) &last_resort, ++ 1, ++ &kCFTypeArrayCallBacks); ++ CFRelease (last_resort); ++ CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault, ++ (const void **) &kCTFontCascadeListAttribute, ++ (const void **) &cascade_list, ++ 1, ++ &kCFTypeDictionaryKeyCallBacks, ++ &kCFTypeDictionaryValueCallBacks); ++ CFRelease (cascade_list); ++ ++ CTFontDescriptorRef new_font_desc = CTFontDescriptorCreateWithAttributes (attributes); ++ CFRelease (attributes); ++ ++ CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (data->ct_font, 0.0, NULL, new_font_desc); ++ if (new_ct_font) ++ { ++ CFRelease (data->ct_font); ++ data->ct_font = new_ct_font; ++ } ++ else ++ DEBUG_MSG (CORETEXT, font, "Font copy with empty cascade list failed"); ++ } ++ + if (unlikely (!data->ct_font)) { + DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed"); + free (data); +@@ -678,7 +730,6 @@ + scratch += old_scratch_used; + scratch_size -= old_scratch_used; + } +-retry: + { + string_ref = CFStringCreateWithCharactersNoCopy (NULL, + pchars, chars_len, +@@ -776,6 +827,18 @@ + + buffer->len = 0; + uint32_t status_and = ~0, status_or = 0; ++ double advances_so_far = 0; ++ /* For right-to-left runs, CoreText returns the glyphs positioned such that ++ * any trailing whitespace is to the left of (0,0). Adjust coordinate system ++ * to fix for that. Test with any RTL string with trailing spaces. ++ * https://code.google.com/p/chromium/issues/detail?id=469028 ++ */ ++ if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) ++ { ++ advances_so_far -= CTLineGetTrailingWhitespaceWidth (line); ++ if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) ++ advances_so_far = -advances_so_far; ++ } + + const CFRange range_all = CFRangeMake (0, 0); + +@@ -786,6 +849,10 @@ + status_or |= run_status; + status_and &= run_status; + DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); ++ double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); ++ if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) ++ run_advance = -run_advance; ++ DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); + + /* CoreText does automatic font fallback (AKA "cascading") for characters + * not supported by the requested font, and provides no way to turn it off, +@@ -817,11 +884,9 @@ + * However, even that wouldn't work if we were passed in the CGFont to + * begin with. + * +- * Webkit uses a slightly different approach: it installs LastResort +- * as fallback chain, and then checks PS name of used font against +- * LastResort. That one is safe for any font except for LastResort, +- * as opposed to ours, which can fail if we are using any uninstalled +- * font that has the same name as an installed font. ++ * We might switch to checking PS name against "LastResort". That would ++ * be safe for all fonts except for those named "Last Resort". Might be ++ * better than what we have right now. + * + * See: http://github.com/behdad/harfbuzz/pull/36 + */ +@@ -860,8 +925,14 @@ + goto resize_and_retry; + hb_glyph_info_t *info = buffer->info + buffer->len; + +- CGGlyph notdef = 0; +- double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, ¬def, NULL, 1); ++ hb_codepoint_t notdef = 0; ++ hb_direction_t dir = buffer->props.direction; ++ hb_position_t x_advance, y_advance, x_offset, y_offset; ++ hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance); ++ hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset); ++ hb_position_t advance = x_advance + y_advance; ++ x_offset = -x_offset; ++ y_offset = -y_offset; + + unsigned int old_len = buffer->len; + for (CFIndex j = range.location; j < range.location + range.length; j++) +@@ -875,19 +946,22 @@ + * for this one. */ + continue; + } ++ if (buffer->unicode->is_default_ignorable (ch)) ++ continue; + + info->codepoint = notdef; + info->cluster = log_clusters[j]; + + info->mask = advance; +- info->var1.u32 = 0; +- info->var2.u32 = 0; ++ info->var1.i32 = x_offset; ++ info->var2.i32 = y_offset; + + info++; + buffer->len++; + } + if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + buffer->reverse_range (old_len, buffer->len); ++ advances_so_far += run_advance; + continue; + } + } +@@ -917,7 +991,7 @@ + scratch_size = scratch_size_saved; \ + scratch = scratch_saved; + +- { ++ { /* Setup glyphs */ + SCRATCH_SAVE(); + const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL; + if (!glyphs) { +@@ -941,6 +1015,11 @@ + SCRATCH_RESTORE(); + } + { ++ /* Setup positions. ++ * Note that CoreText does not return advances for glyphs. As such, ++ * for all but last glyph, we use the delta position to next glyph as ++ * advance (in the advance direction only), and for last glyph we set ++ * whatever is needed to make the whole run's advance add up. */ + SCRATCH_SAVE(); + const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL; + if (!positions) { +@@ -948,33 +1027,42 @@ + CTRunGetPositions (run, range_all, position_buf); + positions = position_buf; + } +- double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL); +- DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); + hb_glyph_info_t *info = run_info; ++ CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult; + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + { ++ hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; + for (unsigned int j = 0; j < num_glyphs; j++) + { +- double advance = (j + 1 < num_glyphs ? positions[j + 1].x : positions[0].x + run_advance) - positions[j].x; +- info->mask = advance; +- info->var1.u32 = positions[0].x; /* Yes, zero. */ +- info->var2.u32 = positions[j].y; ++ double advance; ++ if (likely (j + 1 < num_glyphs)) ++ advance = positions[j + 1].x - positions[j].x; ++ else /* last glyph */ ++ advance = run_advance - (positions[j].x - positions[0].x); ++ info->mask = advance * x_mult; ++ info->var1.i32 = x_offset; ++ info->var2.i32 = positions[j].y * y_mult; + info++; + } + } + else + { +- run_advance = -run_advance; ++ hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult; + for (unsigned int j = 0; j < num_glyphs; j++) + { +- double advance = (j + 1 < num_glyphs ? positions[j + 1].y : positions[0].y + run_advance) - positions[j].y; +- info->mask = advance; +- info->var1.u32 = positions[j].x; +- info->var2.u32 = positions[0].y; /* Yes, zero. */ ++ double advance; ++ if (likely (j + 1 < num_glyphs)) ++ advance = positions[j + 1].y - positions[j].y; ++ else /* last glyph */ ++ advance = run_advance - (positions[j].y - positions[0].y); ++ info->mask = advance * y_mult; ++ info->var1.i32 = positions[j].x * x_mult; ++ info->var2.i32 = y_offset; + info++; + } + } + SCRATCH_RESTORE(); ++ advances_so_far += run_advance; + } + #undef SCRATCH_RESTORE + #undef SCRATCH_SAVE +@@ -984,10 +1072,20 @@ + buffer->len += num_glyphs; + } + +- /* Make sure all runs had the expected direction. */ +- bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); +- assert (bool (status_and & kCTRunStatusRightToLeft) == backward); +- assert (bool (status_or & kCTRunStatusRightToLeft) == backward); ++ /* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel, ++ * or if it does, it doesn't resepct it. So we get runs with wrong ++ * directions. As such, disable the assert... It wouldn't crash, but ++ * cursoring will be off... ++ * ++ * http://crbug.com/419769 ++ */ ++ if (0) ++ { ++ /* Make sure all runs had the expected direction. */ ++ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); ++ assert (bool (status_and & kCTRunStatusRightToLeft) == backward); ++ assert (bool (status_or & kCTRunStatusRightToLeft) == backward); ++ } + + buffer->clear_positions (); + +@@ -998,16 +1096,16 @@ + for (unsigned int i = 0; i < count; i++) + { + pos->x_advance = info->mask; +- pos->x_offset = info->var1.u32; +- pos->y_offset = info->var2.u32; ++ pos->x_offset = info->var1.i32; ++ pos->y_offset = info->var2.i32; + info++, pos++; + } + else + for (unsigned int i = 0; i < count; i++) + { + pos->y_advance = info->mask; +- pos->x_offset = info->var1.u32; +- pos->y_offset = info->var2.u32; ++ pos->x_offset = info->var1.i32; ++ pos->y_offset = info->var2.i32; + info++, pos++; + } + +@@ -1065,10 +1163,6 @@ + * AAT shaper + */ + +-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) +-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) +- +- + /* + * shaper face data + */ +diff -uN gfx/harfbuzz/src_old/hb-coretext.h gfx/harfbuzz/src/hb-coretext.h +--- gfx/harfbuzz/src_old/hb-coretext.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-coretext.h 2016-06-05 23:48:36.098258246 +0200 +@@ -21,7 +21,7 @@ + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * +- * GNU Author(s): Jonathan Kew ++ * Mozilla Author(s): Jonathan Kew + */ + + #ifndef HB_CORETEXT_H +@@ -44,14 +44,14 @@ + #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x') + + +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_coretext_face_create (CGFontRef cg_font); + + +-CGFontRef ++HB_EXTERN CGFontRef + hb_coretext_face_get_cg_font (hb_face_t *face); + +-CTFontRef ++HB_EXTERN CTFontRef + hb_coretext_font_get_ct_font (hb_font_t *font); + + +diff -uN gfx/harfbuzz/src_old/hb-directwrite.cc gfx/harfbuzz/src/hb-directwrite.cc +--- gfx/harfbuzz/src_old/hb-directwrite.cc 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/hb-directwrite.cc 2016-06-05 23:48:38.757243479 +0200 +@@ -0,0 +1,827 @@ ++/* ++ * Copyright © 2015 Ebrahim Byagowi ++ * ++ * This is part of HarfBuzz, a text shaping library. ++ * ++ * Permission is hereby granted, without written agreement and without ++ * license or royalty fees, to use, copy, modify, and distribute this ++ * software and its documentation for any purpose, provided that the ++ * above copyright notice and the following two paragraphs appear in ++ * all copies of this software. ++ * ++ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR ++ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN ++ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, ++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ++ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO ++ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ++ */ ++ ++#define HB_SHAPER directwrite ++#include "hb-shaper-impl-private.hh" ++ ++#include ++ ++#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::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 (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(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 (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(&dwriteFactory) ++ ); ++ ++ IDWriteGdiInterop *gdiInterop; ++ dwriteFactory->GetGdiInterop (&gdiInterop); ++ IDWriteFontFace* fontFace; ++ gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace); ++ ++ IDWriteTextAnalyzer* analyzer; ++ dwriteFactory->CreateTextAnalyzer (&analyzer); ++ ++ unsigned int scratch_size; ++ hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size); ++#define ALLOCATE_ARRAY(Type, name, len) \ ++ Type *name = (Type *) scratch; \ ++ { \ ++ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ ++ assert (_consumed <= scratch_size); \ ++ scratch += _consumed; \ ++ scratch_size -= _consumed; \ ++ } ++ ++#define utf16_index() var1.u32 ++ ++ ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2); ++ ++ unsigned int chars_len = 0; ++ for (unsigned int i = 0; i < buffer->len; i++) ++ { ++ hb_codepoint_t c = buffer->info[i].codepoint; ++ buffer->info[i].utf16_index() = chars_len; ++ if (likely(c <= 0xFFFFu)) ++ pchars[chars_len++] = c; ++ else if (unlikely(c > 0x10FFFFu)) ++ pchars[chars_len++] = 0xFFFDu; ++ else { ++ pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); ++ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); ++ } ++ } ++ ++ ALLOCATE_ARRAY(WORD, log_clusters, chars_len); ++ if (num_features) ++ { ++ /* Need log_clusters to assign features. */ ++ chars_len = 0; ++ for (unsigned int i = 0; i < buffer->len; i++) ++ { ++ hb_codepoint_t c = buffer->info[i].codepoint; ++ unsigned int cluster = buffer->info[i].cluster; ++ log_clusters[chars_len++] = cluster; ++ if (hb_in_range(c, 0x10000u, 0x10FFFFu)) ++ log_clusters[chars_len++] = cluster; /* Surrogates. */ ++ } ++ } ++ ++ HRESULT hr; ++ // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES ++ ++ DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? ++ DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : ++ DWRITE_READING_DIRECTION_LEFT_TO_RIGHT; ++ ++ /* ++ * There's an internal 16-bit limit on some things inside the analyzer, ++ * but we never attempt to shape a word longer than 64K characters ++ * in a single gfxShapedWord, so we cannot exceed that limit. ++ */ ++ UINT32 length = buffer->len; ++ ++ TextAnalysis analysis(pchars, length, NULL, readingDirection); ++ TextAnalysis::Run *runHead; ++ hr = analysis.GenerateResults(analyzer, &runHead); ++ ++ if (FAILED(hr)) { ++ //NS_WARNING("Analyzer failed to generate results."); ++ return false; ++ } ++ ++ UINT32 maxGlyphs = 3 * length / 2 + 16; ++ ++#define INITIAL_GLYPH_SIZE 400 ++ UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); ++ UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); ++ DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*) ++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES)); ++ DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*) ++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES)); ++ ++ UINT32 actualGlyphs; ++ ++ bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction); ++ ++ wchar_t lang[4]; ++ mbstowcs(lang, hb_language_to_string(buffer->props.language), 4); ++ hr = analyzer->GetGlyphs(pchars, length, ++ fontFace, FALSE, ++ buffer->props.direction, ++ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0, ++ maxGlyphs, clusters, textProperties, ++ glyphs, glyphProperties, &actualGlyphs); ++ ++ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { ++ free(clusters); ++ free(glyphs); ++ free(textProperties); ++ free(glyphProperties); ++ ++ clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); ++ glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16)); ++ textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*) ++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES)); ++ glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*) ++ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES)); ++ ++ hr = analyzer->GetGlyphs(pchars, length, ++ fontFace, FALSE, ++ buffer->props.direction, ++ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0, ++ maxGlyphs, clusters, textProperties, ++ glyphs, glyphProperties, &actualGlyphs); ++ } ++ if (FAILED(hr)) { ++ //NS_WARNING("Analyzer failed to get glyphs."); ++ return false; ++ } ++ ++ FLOAT advances[400]; ++ DWRITE_GLYPH_OFFSET offsets[400]; ++ ++ ++ /* The -2 in the following is to compensate for possible ++ * alignment needed after the WORD array. sizeof(WORD) == 2. */ ++ unsigned int glyphs_size = (scratch_size * sizeof (int)-2) ++ / (sizeof (WORD) + ++ 4 + // sizeof (SCRIPT_GLYPHPROP) + ++ sizeof (int) + ++ 8 + // sizeof (GOFFSET) + ++ sizeof (uint32_t)); ++ ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size); ++ ++#undef ALLOCATE_ARRAY ++ ++ hr = analyzer->GetGlyphPlacements(pchars, ++ clusters, ++ textProperties, ++ length, ++ glyphs, ++ glyphProperties, ++ actualGlyphs, ++ fontFace, ++ face->get_upem(), ++ FALSE, ++ FALSE, ++ &runHead->mScript, ++ NULL, ++ NULL, ++ NULL, ++ 0, ++ advances, ++ offsets); ++ ++ if (FAILED(hr)) { ++ //NS_WARNING("Analyzer failed to get glyph placements."); ++ return false; ++ } ++ ++ unsigned int glyphs_len = actualGlyphs; ++ ++ /* Ok, we've got everything we need, now compose output buffer, ++ * very, *very*, carefully! */ ++ ++ /* Calculate visual-clusters. That's what we ship. */ ++ for (unsigned int i = 0; i < glyphs_len; i++) ++ vis_clusters[i] = -1; ++ for (unsigned int i = 0; i < buffer->len; i++) { ++ uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; ++ //*p = MIN (*p, buffer->info[i].cluster); ++ } ++ for (unsigned int i = 1; i < glyphs_len; i++) ++ if (vis_clusters[i] == -1) ++ vis_clusters[i] = vis_clusters[i - 1]; ++ ++#undef utf16_index ++ ++ //if (unlikely (!buffer->ensure (glyphs_len))) ++ // FAIL ("Buffer in error"); ++ ++#undef FAIL ++ ++ /* Set glyph infos */ ++ buffer->len = 0; ++ for (unsigned int i = 0; i < glyphs_len; i++) ++ { ++ hb_glyph_info_t *info = &buffer->info[buffer->len++]; ++ ++ info->codepoint = glyphs[i]; ++ info->cluster = vis_clusters[i]; ++ ++ /* The rest is crap. Let's store position info there for now. */ ++ info->mask = advances[i]; ++ info->var1.u32 = offsets[i].ascenderOffset; ++ info->var2.u32 = -offsets[i].advanceOffset; ++ } ++ ++ free(clusters); ++ free(glyphs); ++ free(textProperties); ++ free(glyphProperties); ++ ++ /* Set glyph positions */ ++ buffer->clear_positions (); ++ for (unsigned int i = 0; i < glyphs_len; i++) ++ { ++ hb_glyph_info_t *info = &buffer->info[i]; ++ hb_glyph_position_t *pos = &buffer->pos[i]; ++ ++ /* TODO vertical */ ++ pos->x_advance = info->mask; ++ pos->x_offset = backward ? -info->var1.u32 : info->var1.u32; ++ pos->y_offset = info->var2.u32; ++ } ++ ++ if (backward) ++ hb_buffer_reverse (buffer); ++ ++ /* Wow, done! */ ++ return true; ++} +diff -uN gfx/harfbuzz/src_old/hb-directwrite.h gfx/harfbuzz/src/hb-directwrite.h +--- gfx/harfbuzz/src_old/hb-directwrite.h 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/hb-directwrite.h 2016-06-05 23:48:40.059236276 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright © 2015 Ebrahim Byagowi ++ * ++ * This is part of HarfBuzz, a text shaping library. ++ * ++ * Permission is hereby granted, without written agreement and without ++ * license or royalty fees, to use, copy, modify, and distribute this ++ * software and its documentation for any purpose, provided that the ++ * above copyright notice and the following two paragraphs appear in ++ * all copies of this software. ++ * ++ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR ++ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN ++ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, ++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ++ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO ++ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ++ */ ++ ++#ifndef HB_DIRECTWRITE_H ++#define HB_DIRECTWRITE_H ++ ++#include "hb.h" ++ ++HB_BEGIN_DECLS ++ ++HB_END_DECLS ++ ++#endif /* HB_UNISCRIBE_H */ +diff -uN gfx/harfbuzz/src_old/hb-face.cc gfx/harfbuzz/src/hb-face.cc +--- gfx/harfbuzz/src_old/hb-face.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-face.cc 2016-06-05 23:48:42.449223049 +0200 +@@ -77,7 +77,7 @@ + * + * Return value: (transfer full) + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, +@@ -113,7 +113,7 @@ + { + hb_face_for_data_closure_t *closure; + +- closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t)); ++ closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t)); + if (unlikely (!closure)) + return NULL; + +@@ -157,7 +157,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_face_create (hb_blob_t *blob, +@@ -165,8 +165,8 @@ + { + hb_face_t *face; + +- if (unlikely (!blob || !hb_blob_get_length (blob))) +- return hb_face_get_empty (); ++ if (unlikely (!blob)) ++ blob = hb_blob_get_empty (); + + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer::sanitize (hb_blob_reference (blob)), index); + +@@ -189,7 +189,7 @@ + * + * Return value: (transfer full) + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_face_get_empty (void) +@@ -206,7 +206,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_face_reference (hb_face_t *face) +@@ -220,7 +220,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_face_destroy (hb_face_t *face) +@@ -257,7 +257,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_face_set_user_data (hb_face_t *face, +@@ -278,7 +278,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void * + hb_face_get_user_data (hb_face_t *face, +@@ -293,7 +293,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_face_make_immutable (hb_face_t *face) +@@ -312,7 +312,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_face_is_immutable (hb_face_t *face) +@@ -330,7 +330,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_face_reference_table (hb_face_t *face, +@@ -347,7 +347,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_blob_t * + hb_face_reference_blob (hb_face_t *face) +@@ -362,7 +362,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_face_set_index (hb_face_t *face, +@@ -382,7 +382,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + unsigned int + hb_face_get_index (hb_face_t *face) +@@ -397,7 +397,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_face_set_upem (hb_face_t *face, +@@ -417,7 +417,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + unsigned int + hb_face_get_upem (hb_face_t *face) +@@ -441,7 +441,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + void + hb_face_set_glyph_count (hb_face_t *face, +@@ -461,7 +461,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.7 + **/ + unsigned int + hb_face_get_glyph_count (hb_face_t *face) +diff -uN gfx/harfbuzz/src_old/hb-face.h gfx/harfbuzz/src/hb-face.h +--- gfx/harfbuzz/src_old/hb-face.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-face.h 2016-06-05 23:48:43.669216308 +0200 +@@ -43,28 +43,28 @@ + + typedef struct hb_face_t hb_face_t; + +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_face_create (hb_blob_t *blob, + unsigned int index); + + typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data); + + /* calls destroy() when not needing user_data anymore */ +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, + void *user_data, + hb_destroy_func_t destroy); + +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_face_get_empty (void); + +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_face_reference (hb_face_t *face); + +-void ++HB_EXTERN void + hb_face_destroy (hb_face_t *face); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_face_set_user_data (hb_face_t *face, + hb_user_data_key_t *key, + void * data, +@@ -72,43 +72,43 @@ + hb_bool_t replace); + + +-void * ++HB_EXTERN void * + hb_face_get_user_data (hb_face_t *face, + hb_user_data_key_t *key); + +-void ++HB_EXTERN void + hb_face_make_immutable (hb_face_t *face); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_face_is_immutable (hb_face_t *face); + + +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_face_reference_table (hb_face_t *face, + hb_tag_t tag); + +-hb_blob_t * ++HB_EXTERN hb_blob_t * + hb_face_reference_blob (hb_face_t *face); + +-void ++HB_EXTERN void + hb_face_set_index (hb_face_t *face, + unsigned int index); + +-unsigned int ++HB_EXTERN unsigned int + hb_face_get_index (hb_face_t *face); + +-void ++HB_EXTERN void + hb_face_set_upem (hb_face_t *face, + unsigned int upem); + +-unsigned int ++HB_EXTERN unsigned int + hb_face_get_upem (hb_face_t *face); + +-void ++HB_EXTERN void + hb_face_set_glyph_count (hb_face_t *face, + unsigned int glyph_count); + +-unsigned int ++HB_EXTERN unsigned int + hb_face_get_glyph_count (hb_face_t *face); + + +diff -uN gfx/harfbuzz/src_old/hb-fallback-shape.cc gfx/harfbuzz/src/hb-fallback-shape.cc +--- gfx/harfbuzz/src_old/hb-fallback-shape.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-fallback-shape.cc 2016-06-05 23:48:44.900209512 +0200 +@@ -106,7 +106,7 @@ + */ + + hb_codepoint_t space; +- bool has_space = font->get_glyph (' ', 0, &space); ++ bool has_space = (bool) font->get_glyph (' ', 0, &space); + + buffer->clear_positions (); + +diff -uN gfx/harfbuzz/src_old/hb-font.cc gfx/harfbuzz/src/hb-font.cc +--- gfx/harfbuzz/src_old/hb-font.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-font.cc 2016-06-05 23:48:47.920192879 +0200 +@@ -45,130 +45,224 @@ + */ + + static hb_bool_t +-hb_font_get_glyph_nil (hb_font_t *font, ++hb_font_get_font_h_extents_nil (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) ++{ ++ memset (metrics, 0, sizeof (*metrics)); ++ return false; ++} ++static hb_bool_t ++hb_font_get_font_h_extents_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_font_h_extents (metrics); ++ if (ret) { ++ metrics->ascender = font->parent_scale_y_distance (metrics->ascender); ++ metrics->descender = font->parent_scale_y_distance (metrics->descender); ++ metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap); ++ } ++ return ret; ++} ++ ++static hb_bool_t ++hb_font_get_font_v_extents_nil (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) ++{ ++ memset (metrics, 0, sizeof (*metrics)); ++ return false; ++} ++static hb_bool_t ++hb_font_get_font_v_extents_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_font_v_extents (metrics); ++ if (ret) { ++ metrics->ascender = font->parent_scale_x_distance (metrics->ascender); ++ metrics->descender = font->parent_scale_x_distance (metrics->descender); ++ metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap); ++ } ++ return ret; ++} ++ ++static hb_bool_t ++hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent->get_glyph (unicode, variation_selector, glyph); +- + *glyph = 0; + return false; + } ++static hb_bool_t ++hb_font_get_glyph_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t unicode, ++ hb_codepoint_t variation_selector, ++ hb_codepoint_t *glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent->get_glyph (unicode, variation_selector, glyph); ++} + + static hb_position_t +-hb_font_get_glyph_h_advance_nil (hb_font_t *font, ++hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); +- + return font->x_scale; + } ++static hb_position_t ++hb_font_get_glyph_h_advance_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph)); ++} + + static hb_position_t +-hb_font_get_glyph_v_advance_nil (hb_font_t *font, ++hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); +- + return font->y_scale; + } ++static hb_position_t ++hb_font_get_glyph_v_advance_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph)); ++} + + static hb_bool_t +-hb_font_get_glyph_h_origin_nil (hb_font_t *font, ++hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) + { +- if (font->parent) { +- hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); +- if (ret) +- font->parent_scale_position (x, y); +- return ret; +- } +- + *x = *y = 0; +- return false; ++ return true; ++} ++static hb_bool_t ++hb_font_get_glyph_h_origin_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ hb_position_t *x, ++ hb_position_t *y, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); ++ if (ret) ++ font->parent_scale_position (x, y); ++ return ret; + } + + static hb_bool_t +-hb_font_get_glyph_v_origin_nil (hb_font_t *font, ++hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) + { +- if (font->parent) { +- hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); +- if (ret) +- font->parent_scale_position (x, y); +- return ret; +- } +- + *x = *y = 0; + return false; + } ++static hb_bool_t ++hb_font_get_glyph_v_origin_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ hb_position_t *x, ++ hb_position_t *y, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); ++ if (ret) ++ font->parent_scale_position (x, y); ++ return ret; ++} + + static hb_position_t +-hb_font_get_glyph_h_kerning_nil (hb_font_t *font, ++hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); +- + return 0; + } ++static hb_position_t ++hb_font_get_glyph_h_kerning_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t left_glyph, ++ hb_codepoint_t right_glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); ++} + + static hb_position_t +-hb_font_get_glyph_v_kerning_nil (hb_font_t *font, ++hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); +- + return 0; + } ++static hb_position_t ++hb_font_get_glyph_v_kerning_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t top_glyph, ++ hb_codepoint_t bottom_glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); ++} + + static hb_bool_t +-hb_font_get_glyph_extents_nil (hb_font_t *font, ++hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) + { +- if (font->parent) { +- hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); +- if (ret) { +- font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); +- font->parent_scale_distance (&extents->width, &extents->height); +- } +- return ret; +- } +- + memset (extents, 0, sizeof (*extents)); + return false; + } ++static hb_bool_t ++hb_font_get_glyph_extents_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ hb_glyph_extents_t *extents, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); ++ if (ret) { ++ font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); ++ font->parent_scale_distance (&extents->width, &extents->height); ++ } ++ return ret; ++} + + static hb_bool_t +-hb_font_get_glyph_contour_point_nil (hb_font_t *font, ++hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, +@@ -176,45 +270,63 @@ + hb_position_t *y, + void *user_data HB_UNUSED) + { +- if (font->parent) { +- hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); +- if (ret) +- font->parent_scale_position (x, y); +- return ret; +- } +- + *x = *y = 0; + return false; + } ++static hb_bool_t ++hb_font_get_glyph_contour_point_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ unsigned int point_index, ++ hb_position_t *x, ++ hb_position_t *y, ++ void *user_data HB_UNUSED) ++{ ++ hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); ++ if (ret) ++ font->parent_scale_position (x, y); ++ return ret; ++} + + static hb_bool_t +-hb_font_get_glyph_name_nil (hb_font_t *font, ++hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent->get_glyph_name (glyph, name, size); +- + if (size) *name = '\0'; + return false; + } ++static hb_bool_t ++hb_font_get_glyph_name_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ hb_codepoint_t glyph, ++ char *name, unsigned int size, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent->get_glyph_name (glyph, name, size); ++} + + static hb_bool_t +-hb_font_get_glyph_from_name_nil (hb_font_t *font, ++hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + { +- if (font->parent) +- return font->parent->get_glyph_from_name (name, len, glyph); +- + *glyph = 0; + return false; + } +- ++static hb_bool_t ++hb_font_get_glyph_from_name_parent (hb_font_t *font, ++ void *font_data HB_UNUSED, ++ const char *name, int len, /* -1 means nul-terminated */ ++ hb_codepoint_t *glyph, ++ void *user_data HB_UNUSED) ++{ ++ return font->parent->get_glyph_from_name (name, len, glyph); ++} + + static const hb_font_funcs_t _hb_font_funcs_nil = { + HB_OBJECT_HEADER_STATIC, +@@ -222,9 +334,44 @@ + true, /* immutable */ + + { ++#define HB_FONT_FUNC_IMPLEMENT(name) NULL, ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ }, ++ { ++#define HB_FONT_FUNC_IMPLEMENT(name) NULL, ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ }, ++ { ++ { + #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ } ++ } ++}; ++static const hb_font_funcs_t _hb_font_funcs_parent = { ++ HB_OBJECT_HEADER_STATIC, ++ ++ true, /* immutable */ ++ ++ { ++#define HB_FONT_FUNC_IMPLEMENT(name) NULL, ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ }, ++ { ++#define HB_FONT_FUNC_IMPLEMENT(name) NULL, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS + #undef HB_FONT_FUNC_IMPLEMENT ++ }, ++ { ++ { ++#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent, ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ } + } + }; + +@@ -236,7 +383,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_funcs_t * + hb_font_funcs_create (void) +@@ -246,7 +393,7 @@ + if (!(ffuncs = hb_object_create ())) + return hb_font_funcs_get_empty (); + +- ffuncs->get = _hb_font_funcs_nil.get; ++ ffuncs->get = _hb_font_funcs_parent.get; + + return ffuncs; + } +@@ -258,12 +405,12 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_funcs_t * + hb_font_funcs_get_empty (void) + { +- return const_cast (&_hb_font_funcs_nil); ++ return const_cast (&_hb_font_funcs_parent); + } + + /** +@@ -274,7 +421,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_funcs_t * + hb_font_funcs_reference (hb_font_funcs_t *ffuncs) +@@ -288,7 +435,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) +@@ -315,7 +462,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, +@@ -336,7 +483,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void * + hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, +@@ -352,7 +499,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) +@@ -371,7 +518,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) +@@ -398,11 +545,11 @@ + ffuncs->destroy.name (ffuncs->user_data.name); \ + \ + if (func) { \ +- ffuncs->get.name = func; \ ++ ffuncs->get.f.name = func; \ + ffuncs->user_data.name = user_data; \ + ffuncs->destroy.name = destroy; \ + } else { \ +- ffuncs->get.name = hb_font_get_##name##_nil; \ ++ ffuncs->get.f.name = hb_font_get_##name##_parent; \ + ffuncs->user_data.name = NULL; \ + ffuncs->destroy.name = NULL; \ + } \ +@@ -411,10 +558,53 @@ + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS + #undef HB_FONT_FUNC_IMPLEMENT + ++bool ++hb_font_t::has_func (unsigned int i) ++{ ++ if (parent && parent != hb_font_get_empty () && parent->has_func (i)) ++ return true; ++ return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i]; ++} + + /* Public getters */ + + /** ++ * hb_font_get_h_extents: ++ * @font: a font. ++ * @extents: (out): ++ * ++ * ++ * ++ * Return value: ++ * ++ * Since: 1.1.3 ++ **/ ++hb_bool_t ++hb_font_get_h_extents (hb_font_t *font, ++ hb_font_extents_t *extents) ++{ ++ return font->get_font_h_extents (extents); ++} ++ ++/** ++ * hb_font_get_v_extents: ++ * @font: a font. ++ * @extents: (out): ++ * ++ * ++ * ++ * Return value: ++ * ++ * Since: 1.1.3 ++ **/ ++hb_bool_t ++hb_font_get_v_extents (hb_font_t *font, ++ hb_font_extents_t *extents) ++{ ++ return font->get_font_v_extents (extents); ++} ++ ++/** + * hb_font_get_glyph: + * @font: a font. + * @unicode: +@@ -425,7 +615,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph (hb_font_t *font, +@@ -444,7 +634,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_position_t + hb_font_get_glyph_h_advance (hb_font_t *font, +@@ -462,7 +652,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_position_t + hb_font_get_glyph_v_advance (hb_font_t *font, +@@ -482,7 +672,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_h_origin (hb_font_t *font, +@@ -503,7 +693,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_v_origin (hb_font_t *font, +@@ -523,7 +713,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_position_t + hb_font_get_glyph_h_kerning (hb_font_t *font, +@@ -542,7 +732,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_position_t + hb_font_get_glyph_v_kerning (hb_font_t *font, +@@ -561,7 +751,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_extents (hb_font_t *font, +@@ -583,7 +773,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_contour_point (hb_font_t *font, +@@ -604,7 +794,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_name (hb_font_t *font, +@@ -625,7 +815,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_from_name (hb_font_t *font, +@@ -639,6 +829,23 @@ + /* A bit higher-level, and with fallback */ + + /** ++ * hb_font_get_extents_for_direction: ++ * @font: a font. ++ * @direction: ++ * @extents: ++ * ++ * ++ * ++ * Since: 1.1.3 ++ **/ ++void ++hb_font_get_extents_for_direction (hb_font_t *font, ++ hb_direction_t direction, ++ hb_font_extents_t *extents) ++{ ++ return font->get_extents_for_direction (direction, extents); ++} ++/** + * hb_font_get_glyph_advance_for_direction: + * @font: a font. + * @glyph: +@@ -648,7 +855,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_get_glyph_advance_for_direction (hb_font_t *font, +@@ -669,7 +876,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_get_glyph_origin_for_direction (hb_font_t *font, +@@ -690,7 +897,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_add_glyph_origin_for_direction (hb_font_t *font, +@@ -711,7 +918,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, +@@ -733,7 +940,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_get_glyph_kerning_for_direction (hb_font_t *font, +@@ -755,7 +962,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_extents_for_origin (hb_font_t *font, +@@ -779,7 +986,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, +@@ -800,7 +1007,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_glyph_to_string (hb_font_t *font, +@@ -814,7 +1021,7 @@ + /** + * hb_font_glyph_from_string: + * @font: a font. +- * @s: (array length=len): ++ * @s: (array length=len) (element-type uint8_t): + * @len: + * @glyph: (out): + * +@@ -822,7 +1029,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_glyph_from_string (hb_font_t *font, +@@ -845,7 +1052,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_font_create (hb_face_t *face) +@@ -854,15 +1061,16 @@ + + if (unlikely (!face)) + face = hb_face_get_empty (); +- if (unlikely (hb_object_is_inert (face))) +- return hb_font_get_empty (); + if (!(font = hb_object_create ())) + return hb_font_get_empty (); + + hb_face_make_immutable (face); ++ font->parent = hb_font_get_empty (); + font->face = hb_face_reference (face); + font->klass = hb_font_funcs_get_empty (); + ++ font->x_scale = font->y_scale = hb_face_get_upem (face); ++ + return font; + } + +@@ -874,20 +1082,19 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_font_create_sub_font (hb_font_t *parent) + { + if (unlikely (!parent)) +- return hb_font_get_empty (); ++ parent = hb_font_get_empty (); + + hb_font_t *font = hb_font_create (parent->face); + + if (unlikely (hb_object_is_inert (font))) + return font; + +- hb_font_make_immutable (parent); + font->parent = hb_font_reference (parent); + + font->x_scale = parent->x_scale; +@@ -905,7 +1112,7 @@ + * + * Return value: (transfer full) + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_font_get_empty (void) +@@ -918,8 +1125,8 @@ + NULL, /* parent */ + const_cast (&_hb_face_nil), + +- 0, /* x_scale */ +- 0, /* y_scale */ ++ 1000, /* x_scale */ ++ 1000, /* y_scale */ + + 0, /* x_ppem */ + 0, /* y_ppem */ +@@ -946,7 +1153,7 @@ + * + * Return value: (transfer full): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_font_reference (hb_font_t *font) +@@ -960,7 +1167,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_destroy (hb_font_t *font) +@@ -993,7 +1200,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_set_user_data (hb_font_t *font, +@@ -1014,7 +1221,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void * + hb_font_get_user_data (hb_font_t *font, +@@ -1029,7 +1236,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_make_immutable (hb_font_t *font) +@@ -1037,6 +1244,9 @@ + if (unlikely (hb_object_is_inert (font))) + return; + ++ if (font->parent) ++ hb_font_make_immutable (font->parent); ++ + font->immutable = true; + } + +@@ -1048,7 +1258,7 @@ + * + * Return value: + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_bool_t + hb_font_is_immutable (hb_font_t *font) +@@ -1057,6 +1267,32 @@ + } + + /** ++ * hb_font_set_parent: ++ * @font: a font. ++ * @parent: new parent. ++ * ++ * Sets parent font of @font. ++ * ++ * Since: 1.0.5 ++ **/ ++void ++hb_font_set_parent (hb_font_t *font, ++ hb_font_t *parent) ++{ ++ if (font->immutable) ++ return; ++ ++ if (!parent) ++ parent = hb_font_get_empty (); ++ ++ hb_font_t *old = font->parent; ++ ++ font->parent = hb_font_reference (parent); ++ ++ hb_font_destroy (old); ++} ++ ++/** + * hb_font_get_parent: + * @font: a font. + * +@@ -1064,7 +1300,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_font_get_parent (hb_font_t *font) +@@ -1080,7 +1316,7 @@ + * + * Return value: (transfer none): + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_font_get_face (hb_font_t *font) +@@ -1098,7 +1334,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_set_funcs (hb_font_t *font, +@@ -1133,7 +1369,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_set_funcs_data (hb_font_t *font, +@@ -1163,7 +1399,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_set_scale (hb_font_t *font, +@@ -1185,7 +1421,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_get_scale (hb_font_t *font, +@@ -1204,7 +1440,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_set_ppem (hb_font_t *font, +@@ -1226,7 +1462,7 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + void + hb_font_get_ppem (hb_font_t *font, +diff -uN gfx/harfbuzz/src_old/hb-font.h gfx/harfbuzz/src/hb-font.h +--- gfx/harfbuzz/src_old/hb-font.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-font.h 2016-06-05 23:48:49.311185210 +0200 +@@ -46,19 +46,19 @@ + + typedef struct hb_font_funcs_t hb_font_funcs_t; + +-hb_font_funcs_t * ++HB_EXTERN hb_font_funcs_t * + hb_font_funcs_create (void); + +-hb_font_funcs_t * ++HB_EXTERN hb_font_funcs_t * + hb_font_funcs_get_empty (void); + +-hb_font_funcs_t * ++HB_EXTERN hb_font_funcs_t * + hb_font_funcs_reference (hb_font_funcs_t *ffuncs); + +-void ++HB_EXTERN void + hb_font_funcs_destroy (hb_font_funcs_t *ffuncs); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key, + void * data, +@@ -66,31 +66,56 @@ + hb_bool_t replace); + + +-void * ++HB_EXTERN void * + hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key); + + +-void ++HB_EXTERN void + hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); + + +-/* glyph extents */ ++/* font and glyph extents */ + ++/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */ ++typedef struct hb_font_extents_t ++{ ++ hb_position_t ascender; /* typographic ascender. */ ++ hb_position_t descender; /* typographic descender. */ ++ hb_position_t line_gap; /* suggested line spacing gap. */ ++ /*< private >*/ ++ hb_position_t reserved9; ++ hb_position_t reserved8; ++ hb_position_t reserved7; ++ hb_position_t reserved6; ++ hb_position_t reserved5; ++ hb_position_t reserved4; ++ hb_position_t reserved3; ++ hb_position_t reserved2; ++ hb_position_t reserved1; ++} hb_font_extents_t; ++ ++/* Note that height is negative in coordinate systems that grow up. */ + typedef struct hb_glyph_extents_t + { +- hb_position_t x_bearing; +- hb_position_t y_bearing; +- hb_position_t width; +- hb_position_t height; ++ hb_position_t x_bearing; /* left side of glyph from origin. */ ++ hb_position_t y_bearing; /* top side of glyph from origin. */ ++ hb_position_t width; /* distance from left to right side. */ ++ hb_position_t height; /* distance from top to bottom side. */ + } hb_glyph_extents_t; + +- + /* func types */ + ++typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data, ++ hb_font_extents_t *metrics, ++ void *user_data); ++typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t; ++typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t; ++ ++ + typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, +@@ -140,6 +165,38 @@ + /* func setters */ + + /** ++ * hb_font_funcs_set_font_h_extents_func: ++ * @ffuncs: font functions. ++ * @func: (closure user_data) (destroy destroy) (scope notified): ++ * @user_data: ++ * @destroy: ++ * ++ * ++ * ++ * Since: 1.1.2 ++ **/ ++HB_EXTERN void ++hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs, ++ hb_font_get_font_h_extents_func_t func, ++ void *user_data, hb_destroy_func_t destroy); ++ ++/** ++ * hb_font_funcs_set_font_v_extents_func: ++ * @ffuncs: font functions. ++ * @func: (closure user_data) (destroy destroy) (scope notified): ++ * @user_data: ++ * @destroy: ++ * ++ * ++ * ++ * Since: 1.1.2 ++ **/ ++HB_EXTERN void ++hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs, ++ hb_font_get_font_v_extents_func_t func, ++ void *user_data, hb_destroy_func_t destroy); ++ ++/** + * hb_font_funcs_set_glyph_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): +@@ -148,9 +205,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -164,9 +221,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -180,9 +237,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -196,9 +253,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -212,9 +269,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -228,9 +285,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -244,9 +301,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -260,9 +317,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_extents_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -276,9 +333,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_contour_point_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -292,9 +349,9 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_name_func_t func, + void *user_data, hb_destroy_func_t destroy); +@@ -308,59 +365,65 @@ + * + * + * +- * Since: 1.0 ++ * Since: 0.9.2 + **/ +-void ++HB_EXTERN void + hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_from_name_func_t func, + void *user_data, hb_destroy_func_t destroy); + +- + /* func dispatch */ + +-hb_bool_t ++HB_EXTERN hb_bool_t ++hb_font_get_h_extents (hb_font_t *font, ++ hb_font_extents_t *extents); ++HB_EXTERN hb_bool_t ++hb_font_get_v_extents (hb_font_t *font, ++ hb_font_extents_t *extents); ++ ++HB_EXTERN hb_bool_t + hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph); + +-hb_position_t ++HB_EXTERN hb_position_t + hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph); +-hb_position_t ++HB_EXTERN hb_position_t + hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); + +-hb_position_t ++HB_EXTERN hb_position_t + hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); +-hb_position_t ++HB_EXTERN hb_position_t + hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, unsigned int size); +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph); +@@ -368,52 +431,56 @@ + + /* high-level funcs, with fallback */ + +-void ++HB_EXTERN void ++hb_font_get_extents_for_direction (hb_font_t *font, ++ hb_direction_t direction, ++ hb_font_extents_t *extents); ++HB_EXTERN void + hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +-void ++HB_EXTERN void + hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +-void ++HB_EXTERN void + hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +-void ++HB_EXTERN void + hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + +-void ++HB_EXTERN void + hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + + /* Generates gidDDD if glyph has no name. */ +-void ++HB_EXTERN void + hb_font_glyph_to_string (hb_font_t *font, + hb_codepoint_t glyph, + char *s, unsigned int size); + /* Parses gidDDD and uniUUUU strings automatically. */ +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_glyph_from_string (hb_font_t *font, + const char *s, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph); +@@ -425,22 +492,22 @@ + + /* Fonts are very light-weight objects */ + +-hb_font_t * ++HB_EXTERN hb_font_t * + hb_font_create (hb_face_t *face); + +-hb_font_t * ++HB_EXTERN hb_font_t * + hb_font_create_sub_font (hb_font_t *parent); + +-hb_font_t * ++HB_EXTERN hb_font_t * + hb_font_get_empty (void); + +-hb_font_t * ++HB_EXTERN hb_font_t * + hb_font_reference (hb_font_t *font); + +-void ++HB_EXTERN void + hb_font_destroy (hb_font_t *font); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_set_user_data (hb_font_t *font, + hb_user_data_key_t *key, + void * data, +@@ -448,42 +515,46 @@ + hb_bool_t replace); + + +-void * ++HB_EXTERN void * + hb_font_get_user_data (hb_font_t *font, + hb_user_data_key_t *key); + +-void ++HB_EXTERN void + hb_font_make_immutable (hb_font_t *font); + +-hb_bool_t ++HB_EXTERN hb_bool_t + hb_font_is_immutable (hb_font_t *font); + +-hb_font_t * ++HB_EXTERN void ++hb_font_set_parent (hb_font_t *font, ++ hb_font_t *parent); ++ ++HB_EXTERN hb_font_t * + hb_font_get_parent (hb_font_t *font); + +-hb_face_t * ++HB_EXTERN hb_face_t * + hb_font_get_face (hb_font_t *font); + + +-void ++HB_EXTERN void + hb_font_set_funcs (hb_font_t *font, + hb_font_funcs_t *klass, + void *font_data, + hb_destroy_func_t destroy); + + /* Be *very* careful with this function! */ +-void ++HB_EXTERN void + hb_font_set_funcs_data (hb_font_t *font, + void *font_data, + hb_destroy_func_t destroy); + + +-void ++HB_EXTERN void + hb_font_set_scale (hb_font_t *font, + int x_scale, + int y_scale); + +-void ++HB_EXTERN void + hb_font_get_scale (hb_font_t *font, + int *x_scale, + int *y_scale); +@@ -491,12 +562,12 @@ + /* + * A zero value means "no hinting in that direction" + */ +-void ++HB_EXTERN void + hb_font_set_ppem (hb_font_t *font, + unsigned int x_ppem, + unsigned int y_ppem); + +-void ++HB_EXTERN void + hb_font_get_ppem (hb_font_t *font, + unsigned int *x_ppem, + unsigned int *y_ppem); +diff -uN gfx/harfbuzz/src_old/hb-font-private.hh gfx/harfbuzz/src/hb-font-private.hh +--- gfx/harfbuzz/src_old/hb-font-private.hh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-font-private.hh 2016-06-05 23:48:46.442201028 +0200 +@@ -42,6 +42,8 @@ + */ + + #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ ++ HB_FONT_FUNC_IMPLEMENT (font_h_extents) \ ++ HB_FONT_FUNC_IMPLEMENT (font_v_extents) \ + HB_FONT_FUNC_IMPLEMENT (glyph) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ +@@ -61,14 +63,6 @@ + + hb_bool_t immutable; + +- /* Don't access these directly. Call hb_font_get_*() instead. */ +- +- struct { +-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; +- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +-#undef HB_FONT_FUNC_IMPLEMENT +- } get; +- + struct { + #define HB_FONT_FUNC_IMPLEMENT(name) void *name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +@@ -80,6 +74,16 @@ + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS + #undef HB_FONT_FUNC_IMPLEMENT + } destroy; ++ ++ /* Don't access these directly. Call font->get_*() instead. */ ++ union get_t { ++ struct get_funcs_t { ++#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ } f; ++ void (*array[VAR]) (void); ++ } get; + }; + + +@@ -144,7 +148,36 @@ + + /* Public getters */ + +- inline hb_bool_t has_glyph (hb_codepoint_t unicode) ++ HB_INTERNAL bool has_func (unsigned int i); ++ ++ /* has_* ... */ ++#define HB_FONT_FUNC_IMPLEMENT(name) \ ++ bool \ ++ has_##name##_func (void) \ ++ { \ ++ hb_font_funcs_t *funcs = this->klass; \ ++ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \ ++ return has_func (i); \ ++ } ++ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS ++#undef HB_FONT_FUNC_IMPLEMENT ++ ++ inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents) ++ { ++ memset (extents, 0, sizeof (*extents)); ++ return klass->get.f.font_h_extents (this, user_data, ++ extents, ++ klass->user_data.font_h_extents); ++ } ++ inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents) ++ { ++ memset (extents, 0, sizeof (*extents)); ++ return klass->get.f.font_v_extents (this, user_data, ++ extents, ++ klass->user_data.font_v_extents); ++ } ++ ++ inline bool has_glyph (hb_codepoint_t unicode) + { + hb_codepoint_t glyph; + return get_glyph (unicode, 0, &glyph); +@@ -154,85 +187,85 @@ + hb_codepoint_t *glyph) + { + *glyph = 0; +- return klass->get.glyph (this, user_data, +- unicode, variation_selector, glyph, +- klass->user_data.glyph); ++ return klass->get.f.glyph (this, user_data, ++ unicode, variation_selector, glyph, ++ klass->user_data.glyph); + } + + inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) + { +- return klass->get.glyph_h_advance (this, user_data, +- glyph, +- klass->user_data.glyph_h_advance); ++ return klass->get.f.glyph_h_advance (this, user_data, ++ glyph, ++ klass->user_data.glyph_h_advance); + } + + inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) + { +- return klass->get.glyph_v_advance (this, user_data, +- glyph, +- klass->user_data.glyph_v_advance); ++ return klass->get.f.glyph_v_advance (this, user_data, ++ glyph, ++ klass->user_data.glyph_v_advance); + } + + inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; +- return klass->get.glyph_h_origin (this, user_data, +- glyph, x, y, +- klass->user_data.glyph_h_origin); ++ return klass->get.f.glyph_h_origin (this, user_data, ++ glyph, x, y, ++ klass->user_data.glyph_h_origin); + } + + inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; +- return klass->get.glyph_v_origin (this, user_data, +- glyph, x, y, +- klass->user_data.glyph_v_origin); ++ return klass->get.f.glyph_v_origin (this, user_data, ++ glyph, x, y, ++ klass->user_data.glyph_v_origin); + } + + inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) + { +- return klass->get.glyph_h_kerning (this, user_data, +- left_glyph, right_glyph, +- klass->user_data.glyph_h_kerning); ++ return klass->get.f.glyph_h_kerning (this, user_data, ++ left_glyph, right_glyph, ++ klass->user_data.glyph_h_kerning); + } + + inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) + { +- return klass->get.glyph_v_kerning (this, user_data, +- top_glyph, bottom_glyph, +- klass->user_data.glyph_v_kerning); ++ return klass->get.f.glyph_v_kerning (this, user_data, ++ top_glyph, bottom_glyph, ++ klass->user_data.glyph_v_kerning); + } + + inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph, + hb_glyph_extents_t *extents) + { + memset (extents, 0, sizeof (*extents)); +- return klass->get.glyph_extents (this, user_data, +- glyph, +- extents, +- klass->user_data.glyph_extents); ++ return klass->get.f.glyph_extents (this, user_data, ++ glyph, ++ extents, ++ klass->user_data.glyph_extents); + } + + inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y) + { + *x = *y = 0; +- return klass->get.glyph_contour_point (this, user_data, +- glyph, point_index, +- x, y, +- klass->user_data.glyph_contour_point); ++ return klass->get.f.glyph_contour_point (this, user_data, ++ glyph, point_index, ++ x, y, ++ klass->user_data.glyph_contour_point); + } + + inline hb_bool_t get_glyph_name (hb_codepoint_t glyph, + char *name, unsigned int size) + { + if (size) *name = '\0'; +- return klass->get.glyph_name (this, user_data, +- glyph, +- name, size, +- klass->user_data.glyph_name); ++ return klass->get.f.glyph_name (this, user_data, ++ glyph, ++ name, size, ++ klass->user_data.glyph_name); + } + + inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */ +@@ -240,15 +273,35 @@ + { + *glyph = 0; + if (len == -1) len = strlen (name); +- return klass->get.glyph_from_name (this, user_data, +- name, len, +- glyph, +- klass->user_data.glyph_from_name); ++ return klass->get.f.glyph_from_name (this, user_data, ++ name, len, ++ glyph, ++ klass->user_data.glyph_from_name); + } + + + /* A bit higher-level, and with fallback */ + ++ inline void get_extents_for_direction (hb_direction_t direction, ++ hb_font_extents_t *extents) ++ { ++ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { ++ if (!get_font_h_extents (extents)) ++ { ++ extents->ascender = y_scale * .8; ++ extents->descender = y_scale - extents->ascender; ++ extents->line_gap = 0; ++ } ++ } else { ++ if (!get_font_v_extents (extents)) ++ { ++ extents->ascender = x_scale / 2; ++ extents->descender = x_scale - extents->ascender; ++ extents->line_gap = 0; ++ } ++ } ++ } ++ + inline void get_glyph_advance_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +@@ -268,7 +321,7 @@ + { + *x = get_glyph_h_advance (glyph) / 2; + +- /* TODO use font_metics.ascent */ ++ /* TODO use font_extents.ascender */ + *y = y_scale; + } + +@@ -298,6 +351,26 @@ + } + } + ++ inline void add_glyph_h_origin (hb_codepoint_t glyph, ++ hb_position_t *x, hb_position_t *y) ++ { ++ hb_position_t origin_x, origin_y; ++ ++ get_glyph_h_origin (glyph, &origin_x, &origin_y); ++ ++ *x += origin_x; ++ *y += origin_y; ++ } ++ inline void add_glyph_v_origin (hb_codepoint_t glyph, ++ hb_position_t *x, hb_position_t *y) ++ { ++ hb_position_t origin_x, origin_y; ++ ++ get_glyph_v_origin (glyph, &origin_x, &origin_y); ++ ++ *x += origin_x; ++ *y += origin_y; ++ } + inline void add_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +@@ -310,6 +383,26 @@ + *y += origin_y; + } + ++ inline void subtract_glyph_h_origin (hb_codepoint_t glyph, ++ hb_position_t *x, hb_position_t *y) ++ { ++ hb_position_t origin_x, origin_y; ++ ++ get_glyph_h_origin (glyph, &origin_x, &origin_y); ++ ++ *x -= origin_x; ++ *y -= origin_y; ++ } ++ inline void subtract_glyph_v_origin (hb_codepoint_t glyph, ++ hb_position_t *x, hb_position_t *y) ++ { ++ hb_position_t origin_x, origin_y; ++ ++ get_glyph_v_origin (glyph, &origin_x, &origin_y); ++ ++ *x -= origin_x; ++ *y -= origin_y; ++ } + inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +diff -uN gfx/harfbuzz/src_old/hb-ft.cc gfx/harfbuzz/src/hb-ft.cc +--- gfx/harfbuzz/src_old/hb-ft.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ft.cc 2016-06-05 23:48:50.916176399 +0200 +@@ -1,6 +1,7 @@ + /* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2009 Keith Stribley ++ * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * +@@ -23,6 +24,7 @@ + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod ++ * Google Author(s): Behdad Esfahbod + */ + + #include "hb-private.hh" +@@ -46,10 +48,15 @@ + * In general, this file does a fine job of what it's supposed to do. + * There are, however, things that need more work: + * +- * - We don't handle any load_flags. That definitely has API implications. :( +- * I believe hb_ft_font_create() should take load_flags input. +- * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be +- * buggy. ++ * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. ++ * Have not investigated. ++ * ++ * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything ++ * would work fine. However, we also abuse this API for performing in font-space, ++ * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode ++ * for that, such that no rounding etc happens. As such, we don't set ppem, and ++ * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale ++ * ourselves, like we do in uniscribe, etc. + * + * - We don't handle / allow for emboldening / obliqueing. + * +@@ -59,6 +66,94 @@ + */ + + ++struct hb_ft_font_t ++{ ++ FT_Face ft_face; ++ int load_flags; ++ bool unref; /* Whether to destroy ft_face when done. */ ++}; ++ ++static hb_ft_font_t * ++_hb_ft_font_create (FT_Face ft_face, bool unref) ++{ ++ hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); ++ ++ if (unlikely (!ft_font)) ++ return NULL; ++ ++ ft_font->ft_face = ft_face; ++ ft_font->unref = unref; ++ ++ ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ++ ++ return ft_font; ++} ++ ++static void ++_hb_ft_font_destroy (hb_ft_font_t *ft_font) ++{ ++ if (ft_font->unref) ++ FT_Done_Face (ft_font->ft_face); ++ ++ free (ft_font); ++} ++ ++/** ++ * hb_ft_font_set_load_flags: ++ * @font: ++ * @load_flags: ++ * ++ * ++ * ++ * Since: 1.0.5 ++ **/ ++void ++hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) ++{ ++ if (font->immutable) ++ return; ++ ++ if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) ++ return; ++ ++ hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; ++ ++ ft_font->load_flags = load_flags; ++} ++ ++/** ++ * hb_ft_font_get_load_flags: ++ * @font: ++ * ++ * ++ * ++ * Return value: ++ * Since: 1.0.5 ++ **/ ++int ++hb_ft_font_get_load_flags (hb_font_t *font) ++{ ++ if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) ++ return 0; ++ ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; ++ ++ return ft_font->load_flags; ++} ++ ++FT_Face ++hb_ft_font_get_face (hb_font_t *font) ++{ ++ if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) ++ return NULL; ++ ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; ++ ++ return ft_font->ft_face; ++} ++ ++ ++ + static hb_bool_t + hb_ft_get_glyph (hb_font_t *font HB_UNUSED, + void *font_data, +@@ -68,17 +163,19 @@ + void *user_data HB_UNUSED) + + { +- FT_Face ft_face = (FT_Face) font_data; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ unsigned int g; + +-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX +- if (unlikely (variation_selector)) { +- *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); +- return *glyph != 0; +- } +-#endif ++ if (likely (!variation_selector)) ++ g = FT_Get_Char_Index (ft_font->ft_face, unicode); ++ else ++ g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); + +- *glyph = FT_Get_Char_Index (ft_face, unicode); +- return *glyph != 0; ++ if (unlikely (!g)) ++ return false; ++ ++ *glyph = g; ++ return true; + } + + static hb_position_t +@@ -87,13 +184,15 @@ + hb_codepoint_t glyph, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; +- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Fixed v; + +- if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) ++ if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) + return 0; + ++ if (font->x_scale < 0) ++ v = -v; ++ + return (v + (1<<9)) >> 10; + } + +@@ -103,31 +202,21 @@ + hb_codepoint_t glyph, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; +- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Fixed v; + +- if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) ++ if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) + return 0; + ++ if (font->y_scale < 0) ++ v = -v; ++ + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + return (-v + (1<<9)) >> 10; + } + + static hb_bool_t +-hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, +- void *font_data HB_UNUSED, +- hb_codepoint_t glyph HB_UNUSED, +- hb_position_t *x HB_UNUSED, +- hb_position_t *y HB_UNUSED, +- void *user_data HB_UNUSED) +-{ +- /* We always work in the horizontal coordinates. */ +- return true; +-} +- +-static hb_bool_t + hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, +@@ -135,10 +224,10 @@ + hb_position_t *y, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; +- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ FT_Face ft_face = ft_font->ft_face; + +- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) ++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates +@@ -146,6 +235,11 @@ + *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; + *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); + ++ if (font->x_scale < 0) ++ *x = -*x; ++ if (font->y_scale < 0) ++ *y = -*y; ++ + return true; + } + +@@ -156,27 +250,16 @@ + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Vector kerningv; + + FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; +- if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv)) ++ if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) + return 0; + + return kerningv.x; + } + +-static hb_position_t +-hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, +- void *font_data HB_UNUSED, +- hb_codepoint_t top_glyph HB_UNUSED, +- hb_codepoint_t bottom_glyph HB_UNUSED, +- void *user_data HB_UNUSED) +-{ +- /* FreeType API doesn't support vertical kerning */ +- return 0; +-} +- + static hb_bool_t + hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, + void *font_data, +@@ -184,16 +267,26 @@ + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; +- int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ FT_Face ft_face = ft_font->ft_face; + +- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) ++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + extents->x_bearing = ft_face->glyph->metrics.horiBearingX; + extents->y_bearing = ft_face->glyph->metrics.horiBearingY; + extents->width = ft_face->glyph->metrics.width; + extents->height = -ft_face->glyph->metrics.height; ++ if (font->x_scale < 0) ++ { ++ extents->x_bearing = -extents->x_bearing; ++ extents->width = -extents->width; ++ } ++ if (font->y_scale < 0) ++ { ++ extents->y_bearing = -extents->y_bearing; ++ extents->height = -extents->height; ++ } + return true; + } + +@@ -206,10 +299,10 @@ + hb_position_t *y, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; +- int load_flags = FT_LOAD_DEFAULT; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ FT_Face ft_face = ft_font->ft_face; + +- if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) ++ if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) + return false; + + if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) +@@ -231,9 +324,9 @@ + char *name, unsigned int size, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + +- hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); ++ hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); + if (ret && (size && !*name)) + ret = false; + +@@ -247,7 +340,8 @@ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + { +- FT_Face ft_face = (FT_Face) font_data; ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ FT_Face ft_face = ft_font->ft_face; + + if (len < 0) + *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); +@@ -272,23 +366,76 @@ + return *glyph != 0; + } + ++static hb_bool_t ++hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, ++ void *font_data, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) ++{ ++ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; ++ FT_Face ft_face = ft_font->ft_face; ++ metrics->ascender = ft_face->size->metrics.ascender; ++ metrics->descender = ft_face->size->metrics.descender; ++ metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender); ++ if (font->y_scale < 0) ++ { ++ metrics->ascender = -metrics->ascender; ++ metrics->descender = -metrics->descender; ++ metrics->line_gap = -metrics->line_gap; ++ } ++ return true; ++} ++ ++static hb_font_funcs_t *static_ft_funcs = NULL; ++ ++#ifdef HB_USE_ATEXIT ++static ++void free_static_ft_funcs (void) ++{ ++ hb_font_funcs_destroy (static_ft_funcs); ++} ++#endif + +-static hb_font_funcs_t * +-_hb_ft_get_font_funcs (void) ++static void ++_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) + { +- static const hb_font_funcs_t ft_ffuncs = { +- HB_OBJECT_HEADER_STATIC, ++retry: ++ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs); ++ ++ if (unlikely (!funcs)) ++ { ++ funcs = hb_font_funcs_create (); ++ ++ hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL); ++ //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL); ++ hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL); ++ hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL); ++ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL); ++ //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL); ++ hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL); ++ hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL); ++ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL); ++ hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL); ++ hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL); ++ hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL); ++ hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL); + +- true, /* immutable */ ++ hb_font_funcs_make_immutable (funcs); + +- { +-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, +- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +-#undef HB_FONT_FUNC_IMPLEMENT ++ if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) { ++ hb_font_funcs_destroy (funcs); ++ goto retry; + } ++ ++#ifdef HB_USE_ATEXIT ++ atexit (free_static_ft_funcs); /* First person registers atexit() callback. */ ++#endif + }; + +- return const_cast (&ft_ffuncs); ++ hb_font_set_funcs (font, ++ funcs, ++ _hb_ft_font_create (ft_face, unref), ++ (hb_destroy_func_t) _hb_ft_font_destroy); + } + + +@@ -327,7 +474,7 @@ + * + * + * Return value: (transfer full): +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_ft_face_create (FT_Face ft_face, +@@ -340,11 +487,7 @@ + + blob = hb_blob_create ((const char *) ft_face->stream->base, + (unsigned int) ft_face->stream->size, +- /* TODO: We assume that it's mmap()'ed, but FreeType code +- * suggests that there are cases we reach here but font is +- * not mmapped. For example, when mmap() fails. No idea +- * how to deal with it better here. */ +- HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, ++ HB_MEMORY_MODE_READONLY, + ft_face, destroy); + face = hb_face_create (blob, ft_face->face_index); + hb_blob_destroy (blob); +@@ -358,6 +501,22 @@ + return face; + } + ++/** ++ * hb_ft_face_create_referenced: ++ * @ft_face: ++ * ++ * ++ * ++ * Return value: (transfer full): ++ * Since: 0.9.38 ++ **/ ++hb_face_t * ++hb_ft_face_create_referenced (FT_Face ft_face) ++{ ++ FT_Reference_Face (ft_face); ++ return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face); ++} ++ + static void + hb_ft_face_finalize (FT_Face ft_face) + { +@@ -371,7 +530,7 @@ + * + * + * Return value: (transfer full): +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_face_t * + hb_ft_face_create_cached (FT_Face ft_face) +@@ -388,11 +547,6 @@ + return hb_face_reference ((hb_face_t *) ft_face->generic.data); + } + +-static void +-_do_nothing (void) +-{ +-} +- + + /** + * hb_ft_font_create: +@@ -402,7 +556,7 @@ + * + * + * Return value: (transfer full): +- * Since: 1.0 ++ * Since: 0.9.2 + **/ + hb_font_t * + hb_ft_font_create (FT_Face ft_face, +@@ -414,29 +568,47 @@ + face = hb_ft_face_create (ft_face, destroy); + font = hb_font_create (face); + hb_face_destroy (face); +- hb_font_set_funcs (font, +- _hb_ft_get_font_funcs (), +- ft_face, (hb_destroy_func_t) _do_nothing); ++ _hb_ft_font_set_funcs (font, ft_face, false); + hb_font_set_scale (font, + (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16), + (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16)); ++#if 0 /* hb-ft works in no-hinting model */ + hb_font_set_ppem (font, + ft_face->size->metrics.x_ppem, + ft_face->size->metrics.y_ppem); ++#endif + + return font; + } + ++/** ++ * hb_ft_font_create_referenced: ++ * @ft_face: ++ * ++ * ++ * ++ * Return value: (transfer full): ++ * Since: 0.9.38 ++ **/ ++hb_font_t * ++hb_ft_font_create_referenced (FT_Face ft_face) ++{ ++ FT_Reference_Face (ft_face); ++ return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face); ++} ++ + + /* Thread-safe, lock-free, FT_Library */ + + static FT_Library ft_library; + +-static inline ++#ifdef HB_USE_ATEXIT ++static + void free_ft_library (void) + { + FT_Done_FreeType (ft_library); + } ++#endif + + static FT_Library + get_ft_library (void) +@@ -493,30 +665,23 @@ + + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); + +- assert (font->y_scale >= 0); + FT_Set_Char_Size (ft_face, +- font->x_scale, font->y_scale, ++ abs (font->x_scale), abs (font->y_scale), + 0, 0); + #if 0 + font->x_ppem * 72 * 64 / font->x_scale, + font->y_ppem * 72 * 64 / font->y_scale); + #endif ++ if (font->x_scale < 0 || font->y_scale < 0) ++ { ++ FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, ++ 0, font->y_scale < 0 ? -1 : +1}; ++ FT_Set_Transform (ft_face, &matrix, NULL); ++ } + + ft_face->generic.data = blob; + ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; + +- hb_font_set_funcs (font, +- _hb_ft_get_font_funcs (), +- ft_face, +- (hb_destroy_func_t) FT_Done_Face); +-} +- +-FT_Face +-hb_ft_font_get_face (hb_font_t *font) +-{ +- if (font->destroy == (hb_destroy_func_t) FT_Done_Face || +- font->destroy == (hb_destroy_func_t) _do_nothing) +- return (FT_Face) font->user_data; +- +- return NULL; ++ _hb_ft_font_set_funcs (font, ft_face, true); ++ hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); + } +diff -uN gfx/harfbuzz/src_old/hb-ft.h gfx/harfbuzz/src/hb-ft.h +--- gfx/harfbuzz/src_old/hb-ft.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ft.h 2016-06-05 23:48:52.044170188 +0200 +@@ -1,5 +1,6 @@ + /* + * Copyright © 2009 Red Hat, Inc. ++ * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * +@@ -22,6 +23,7 @@ + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod ++ * Google Author(s): Behdad Esfahbod + */ + + #ifndef HB_FT_H +@@ -34,28 +36,90 @@ + + HB_BEGIN_DECLS + +-/* Note: FreeType is not thread-safe. Hence, these functions are not either. */ ++/* ++ * Note: FreeType is not thread-safe. ++ * Hence, these functions are not either. ++ */ + +-hb_face_t * ++/* ++ * hb-face from ft-face. ++ */ ++ ++/* This one creates a new hb-face for given ft-face. ++ * When the returned hb-face is destroyed, the destroy ++ * callback is called (if not NULL), with the ft-face passed ++ * to it. ++ * ++ * The client is responsible to make sure that ft-face is ++ * destroyed after hb-face is destroyed. ++ * ++ * Most often you don't want this function. You should use either ++ * hb_ft_face_create_cached(), or hb_ft_face_create_referenced(). ++ * In particular, if you are going to pass NULL as destroy, you ++ * probably should use (the more recent) hb_ft_face_create_referenced() ++ * instead. ++ */ ++HB_EXTERN hb_face_t * + hb_ft_face_create (FT_Face ft_face, + hb_destroy_func_t destroy); + +-hb_face_t * ++/* This version is like hb_ft_face_create(), except that it caches ++ * the hb-face using the generic pointer of the ft-face. This means ++ * that subsequent calls to this function with the same ft-face will ++ * return the same hb-face (correctly referenced). ++ * ++ * Client is still responsible for making sure that ft-face is destroyed ++ * after hb-face is. ++ */ ++HB_EXTERN hb_face_t * + hb_ft_face_create_cached (FT_Face ft_face); + +-hb_font_t * ++/* This version is like hb_ft_face_create(), except that it calls ++ * FT_Reference_Face() on ft-face, as such keeping ft-face alive ++ * as long as the hb-face is. ++ * ++ * This is the most convenient version to use. Use it unless you have ++ * very good reasons not to. ++ */ ++HB_EXTERN hb_face_t * ++hb_ft_face_create_referenced (FT_Face ft_face); ++ ++ ++/* ++ * hb-font from ft-face. ++ */ ++ ++/* ++ * Note: ++ * ++ * Set face size on ft-face before creating hb-font from it. ++ * Otherwise hb-ft would NOT pick up the font size correctly. ++ */ ++ ++/* See notes on hb_ft_face_create(). Same issues re lifecycle-management ++ * apply here. Use hb_ft_font_create_referenced() if you can. */ ++HB_EXTERN hb_font_t * + hb_ft_font_create (FT_Face ft_face, + hb_destroy_func_t destroy); + ++/* See notes on hb_ft_face_create_referenced() re lifecycle-management ++ * issues. */ ++HB_EXTERN hb_font_t * ++hb_ft_font_create_referenced (FT_Face ft_face); ++ ++HB_EXTERN FT_Face ++hb_ft_font_get_face (hb_font_t *font); ++ ++HB_EXTERN void ++hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); + ++HB_EXTERN int ++hb_ft_font_get_load_flags (hb_font_t *font); + + /* Makes an hb_font_t use FreeType internally to implement font functions. */ +-void ++HB_EXTERN void + hb_ft_font_set_funcs (hb_font_t *font); + +-FT_Face +-hb_ft_font_get_face (hb_font_t *font); +- + + HB_END_DECLS + +diff -uN gfx/harfbuzz/src_old/hb-glib.cc gfx/harfbuzz/src/hb-glib.cc +--- gfx/harfbuzz/src_old/hb-glib.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-glib.cc 2016-06-05 23:48:53.244163610 +0200 +@@ -382,3 +382,19 @@ + return const_cast (&_hb_glib_unicode_funcs); + } + ++/** ++ * hb_glib_blob_create: ++ * ++ * Since: 0.9.38 ++ **/ ++hb_blob_t * ++hb_glib_blob_create (GBytes *gbytes) ++{ ++ gsize size = 0; ++ gconstpointer data = g_bytes_get_data (gbytes, &size); ++ return hb_blob_create ((const char *) data, ++ size, ++ HB_MEMORY_MODE_READONLY, ++ g_bytes_ref (gbytes), ++ (hb_destroy_func_t) g_bytes_unref); ++} +diff -uN gfx/harfbuzz/src_old/hb-glib.h gfx/harfbuzz/src/hb-glib.h +--- gfx/harfbuzz/src_old/hb-glib.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-glib.h 2016-06-05 23:48:54.401157255 +0200 +@@ -36,16 +36,19 @@ + HB_BEGIN_DECLS + + +-hb_script_t ++HB_EXTERN hb_script_t + hb_glib_script_to_script (GUnicodeScript script); + +-GUnicodeScript ++HB_EXTERN GUnicodeScript + hb_glib_script_from_script (hb_script_t script); + + +-hb_unicode_funcs_t * ++HB_EXTERN hb_unicode_funcs_t * + hb_glib_get_unicode_funcs (void); + ++HB_EXTERN hb_blob_t * ++hb_glib_blob_create (GBytes *gbytes); ++ + + HB_END_DECLS + +diff -uN gfx/harfbuzz/src_old/hb-gobject-enums.h.tmpl gfx/harfbuzz/src/hb-gobject-enums.h.tmpl +--- gfx/harfbuzz/src_old/hb-gobject-enums.h.tmpl 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-gobject-enums.h.tmpl 2016-06-05 23:48:57.189141987 +0200 +@@ -42,7 +42,7 @@ + /*** END file-header ***/ + + /*** BEGIN value-header ***/ +-GType @enum_name@_get_type (void) G_GNUC_CONST; ++HB_EXTERN GType @enum_name@_get_type (void) G_GNUC_CONST; + #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) + + /*** END value-header ***/ +diff -uN gfx/harfbuzz/src_old/hb-gobject-structs.cc gfx/harfbuzz/src/hb-gobject-structs.cc +--- gfx/harfbuzz/src_old/hb-gobject-structs.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-gobject-structs.cc 2016-06-05 23:48:58.408135321 +0200 +@@ -54,6 +54,17 @@ + #define HB_DEFINE_OBJECT_TYPE(name) \ + HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy); + ++#define HB_DEFINE_VALUE_TYPE(name) \ ++ static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \ ++ { \ ++ hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \ ++ if (unlikely (!c)) return NULL; \ ++ *c = *l; \ ++ return c; \ ++ } \ ++ static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \ ++ HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy); ++ + HB_DEFINE_OBJECT_TYPE (buffer) + HB_DEFINE_OBJECT_TYPE (blob) + HB_DEFINE_OBJECT_TYPE (face) +@@ -62,59 +73,8 @@ + HB_DEFINE_OBJECT_TYPE (set) + HB_DEFINE_OBJECT_TYPE (shape_plan) + HB_DEFINE_OBJECT_TYPE (unicode_funcs) +- +- +-static hb_feature_t *feature_reference (hb_feature_t *g) +-{ +- hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t)); +- if (unlikely (!c)) return NULL; +- *c = *g; +- return c; +-} +-static void feature_destroy (hb_feature_t *g) { free (g); } +-HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy) +- +-static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g) +-{ +- hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t)); +- if (unlikely (!c)) return NULL; +- *c = *g; +- return c; +-} +-static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); } +-HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy) +- +-static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g) +-{ +- hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t)); +- if (unlikely (!c)) return NULL; +- *c = *g; +- return c; +-} +-static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); } +-HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy) +- +-static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g) +-{ +- hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t)); +- if (unlikely (!c)) return NULL; +- *c = *g; +- return c; +-} +-static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); } +-HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy) +- +-static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; } +-static void user_data_key_destroy (hb_user_data_key_t l) { } +-HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy) +- +- +-static hb_language_t *language_reference (hb_language_t *l) +-{ +- hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t)); +- if (unlikely (!c)) return NULL; +- *c = *l; +- return c; +-} +-static void language_destroy (hb_language_t *l) { free (l); } +-HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy) ++HB_DEFINE_VALUE_TYPE (feature) ++HB_DEFINE_VALUE_TYPE (glyph_info) ++HB_DEFINE_VALUE_TYPE (glyph_position) ++HB_DEFINE_VALUE_TYPE (segment_properties) ++HB_DEFINE_VALUE_TYPE (user_data_key) +diff -uN gfx/harfbuzz/src_old/hb-gobject-structs.h gfx/harfbuzz/src/hb-gobject-structs.h +--- gfx/harfbuzz/src_old/hb-gobject-structs.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-gobject-structs.h 2016-06-05 23:48:59.577128929 +0200 +@@ -40,55 +40,65 @@ + + /* Object types */ + +-GType hb_gobject_blob_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_blob_get_type (void); + #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ()) + +-GType hb_gobject_buffer_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_buffer_get_type (void); + #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ()) + +-GType hb_gobject_face_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_face_get_type (void); + #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) + +-GType hb_gobject_font_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_font_get_type (void); + #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ()) + +-GType hb_gobject_font_funcs_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_font_funcs_get_type (void); + #define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ()) + +-GType hb_gobject_set_get_type (void); ++HB_EXTERN GType hb_gobject_set_get_type (void); + #define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ()) + +-GType hb_gobject_shape_plan_get_type (void); ++HB_EXTERN GType hb_gobject_shape_plan_get_type (void); + #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ()) + +-GType hb_gobject_unicode_funcs_get_type (void); ++/** ++ * Since: 0.9.2 ++ **/ ++HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void); + #define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ()) + + /* Value types */ + +-GType hb_gobject_feature_get_type (void); ++HB_EXTERN GType hb_gobject_feature_get_type (void); + #define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ()) + +-GType hb_gobject_glyph_info_get_type (void); ++HB_EXTERN GType hb_gobject_glyph_info_get_type (void); + #define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ()) + +-GType hb_gobject_glyph_position_get_type (void); ++HB_EXTERN GType hb_gobject_glyph_position_get_type (void); + #define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ()) + +-GType hb_gobject_segment_properties_get_type (void); ++HB_EXTERN GType hb_gobject_segment_properties_get_type (void); + #define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ()) + +-GType hb_gobject_user_data_key_get_type (void); ++HB_EXTERN GType hb_gobject_user_data_key_get_type (void); + #define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ()) + +-/* Currently gobject-introspection doesn't understand that hb_language_t +- * can be passed by-value. As such we box it up. May remove in the +- * future. +- * +- * https://bugzilla.gnome.org/show_bug.cgi?id=707656 +- */ +-GType hb_gobject_language_get_type (void); +-#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ()) + + HB_END_DECLS + +diff -uN gfx/harfbuzz/src_old/hb-graphite2.cc gfx/harfbuzz/src/hb-graphite2.cc +--- gfx/harfbuzz/src_old/hb-graphite2.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-graphite2.cc 2016-06-05 23:49:01.899116257 +0200 +@@ -138,6 +138,9 @@ + free (data); + } + ++/* ++ * Since: 0.9.10 ++ */ + gr_face * + hb_graphite2_face_get_gr_face (hb_face_t *face) + { +@@ -172,6 +175,9 @@ + gr_font_destroy (data); + } + ++/* ++ * Since: 0.9.10 ++ */ + gr_font * + hb_graphite2_font_get_gr_font (hb_font_t *font) + { +@@ -228,12 +234,11 @@ + int lang_len = lang_end ? lang_end - lang : -1; + gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0); + +- while (num_features--) ++ for (unsigned int i = 0; i < num_features; i++) + { +- const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag); ++ const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag); + if (fref) +- gr_fref_set_feature_value (fref, features->value, feats); +- features++; ++ gr_fref_set_feature_value (fref, features[i].value, feats); + } + + gr_segment *seg = NULL; +@@ -249,6 +254,8 @@ + for (unsigned int i = 0; i < buffer->len; ++i) + chars[i] = buffer->info[i].codepoint; + ++ /* TODO ensure_native_direction. */ ++ + hb_tag_t script_tag[2]; + hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]); + +@@ -267,9 +274,11 @@ + if (unlikely (!glyph_count)) { + if (feats) gr_featureval_destroy (feats); + gr_seg_destroy (seg); +- return false; ++ buffer->len = 0; ++ return true; + } + ++ buffer->ensure (glyph_count); + scratch = buffer->get_scratch_buffer (&scratch_size); + while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) + + DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size) +@@ -331,7 +340,6 @@ + } + ci++; + +- //buffer->clear_output (); + for (unsigned int i = 0; i < ci; ++i) + { + for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j) +@@ -342,32 +350,58 @@ + } + } + buffer->len = glyph_count; +- //buffer->swap_buffers (); +- +- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) +- curradvx = gr_seg_advance_X(seg); + +- hb_glyph_position_t *pPos; +- for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg); +- is; pPos++, is = gr_slot_next_in_segment (is)) +- { +- pPos->x_offset = gr_slot_origin_X (is) - curradvx; +- pPos->y_offset = gr_slot_origin_Y (is) - curradvy; +- pPos->x_advance = gr_slot_advance_X (is, grface, grfont); +- pPos->y_advance = gr_slot_advance_Y (is, grface, grfont); +- if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) +- curradvx -= pPos->x_advance; +- pPos->x_offset = gr_slot_origin_X (is) - curradvx; +- if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) ++ float yscale = font->y_scale / font->x_scale; ++ /* Positioning. */ ++ if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) ++ { ++ hb_glyph_position_t *pPos; ++ for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg); ++ is; pPos++, is = gr_slot_next_in_segment (is)) ++ { ++ pPos->x_offset = gr_slot_origin_X (is) - curradvx; ++ pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy; ++ pPos->x_advance = gr_slot_advance_X (is, grface, grfont); ++ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale; + curradvx += pPos->x_advance; +- pPos->y_offset = gr_slot_origin_Y (is) - curradvy; +- curradvy += pPos->y_advance; +- } +- if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) ++ curradvy += pPos->y_advance; ++ } + pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx; +- +- if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) ++ } ++ else ++ { ++ hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL) + buffer->len - 1; ++ const hb_glyph_info_t *info = buffer->info + buffer->len - 1; ++ const hb_glyph_info_t *tinfo; ++ const gr_slot *tis; ++ int currclus = -1; ++ float clusx = 0., clusy = 0.; ++ for (is = gr_seg_last_slot (seg); is; pPos--, info--, is = gr_slot_prev_in_segment (is)) ++ { ++ if (info->cluster != currclus) ++ { ++ curradvx += clusx; ++ curradvy += clusy; ++ currclus = info->cluster; ++ clusx = 0.; ++ clusy = 0.; ++ for (tis = is, tinfo = info; tis && tinfo->cluster == currclus; tis = gr_slot_prev_in_segment (tis), tinfo--) ++ { ++ clusx += gr_slot_advance_X (tis, grface, grfont); ++ clusy += gr_slot_advance_Y (tis, grface, grfont) * yscale; ++ } ++ curradvx += clusx; ++ curradvy += clusy; ++ } ++ pPos->x_advance = gr_slot_advance_X (is, grface, grfont); ++ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale; ++ curradvx -= pPos->x_advance; ++ curradvy -= pPos->y_advance; ++ pPos->x_offset = gr_slot_origin_X (is) - curradvx; ++ pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy; ++ } + hb_buffer_reverse_clusters (buffer); ++ } + + if (feats) gr_featureval_destroy (feats); + gr_seg_destroy (seg); +diff -uN gfx/harfbuzz/src_old/hb-graphite2.h gfx/harfbuzz/src/hb-graphite2.h +--- gfx/harfbuzz/src_old/hb-graphite2.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-graphite2.h 2016-06-05 23:49:03.057109946 +0200 +@@ -36,10 +36,10 @@ + #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f') + + +-gr_face * ++HB_EXTERN gr_face * + hb_graphite2_face_get_gr_face (hb_face_t *face); + +-gr_font * ++HB_EXTERN gr_font * + hb_graphite2_font_get_gr_font (hb_font_t *font); + + +diff -uN gfx/harfbuzz/src_old/hb.h gfx/harfbuzz/src/hb.h +--- gfx/harfbuzz/src_old/hb.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb.h 2016-06-05 23:50:56.057516793 +0200 +@@ -28,6 +28,10 @@ + #define HB_H + #define HB_H_IN + ++#ifndef HB_EXTERN ++#define HB_EXTERN extern ++#endif ++ + #include "hb-blob.h" + #include "hb-buffer.h" + #include "hb-common.h" +diff -uN gfx/harfbuzz/src_old/hb-icu.cc gfx/harfbuzz/src/hb-icu.cc +--- gfx/harfbuzz/src_old/hb-icu.cc 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-icu.cc 2016-06-05 23:49:04.387102711 +0200 +@@ -363,10 +363,8 @@ + if (!hb_atomic_ptr_get (&normalizer)) { + UErrorCode icu_err = U_ZERO_ERROR; + /* We ignore failure in getNFCInstace(). */ +- hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err)); ++ (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err)); + } + #endif + return const_cast (&_hb_icu_unicode_funcs); + } +- +- +diff -uN gfx/harfbuzz/src_old/hb-icu.h gfx/harfbuzz/src/hb-icu.h +--- gfx/harfbuzz/src_old/hb-icu.h 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-icu.h 2016-06-05 23:49:05.565096299 +0200 +@@ -36,14 +36,14 @@ + HB_BEGIN_DECLS + + +-hb_script_t ++HB_EXTERN hb_script_t + hb_icu_script_to_script (UScriptCode script); + +-UScriptCode ++HB_EXTERN UScriptCode + hb_icu_script_from_script (hb_script_t script); + + +-hb_unicode_funcs_t * ++HB_EXTERN hb_unicode_funcs_t * + hb_icu_get_unicode_funcs (void); + + +diff -uN gfx/harfbuzz/src_old/hb-mutex-private.hh gfx/harfbuzz/src/hb-mutex-private.hh +--- gfx/harfbuzz/src_old/hb-mutex-private.hh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-mutex-private.hh 2016-06-05 23:49:06.735089929 +0200 +@@ -39,7 +39,13 @@ + + /* We need external help for these */ + +-#if 0 ++#if defined(HB_MUTEX_IMPL_INIT) \ ++ && defined(hb_mutex_impl_init) \ ++ && defined(hb_mutex_impl_lock) \ ++ && defined(hb_mutex_impl_unlock) \ ++ && defined(hb_mutex_impl_finish) ++ ++/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ + + + #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__)) +@@ -47,7 +53,11 @@ + #include + typedef CRITICAL_SECTION hb_mutex_impl_t; + #define HB_MUTEX_IMPL_INIT {0} ++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) ++#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) ++#else + #define hb_mutex_impl_init(M) InitializeCriticalSection (M) ++#endif + #define hb_mutex_impl_lock(M) EnterCriticalSection (M) + #define hb_mutex_impl_unlock(M) LeaveCriticalSection (M) + #define hb_mutex_impl_finish(M) DeleteCriticalSection (M) +@@ -109,10 +119,12 @@ + #define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END + #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END + ++ + #endif + + + #define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT} ++ + struct hb_mutex_t + { + /* TODO Add tracing. */ +diff -uN gfx/harfbuzz/src_old/hb-object-private.hh gfx/harfbuzz/src/hb-object-private.hh +--- gfx/harfbuzz/src_old/hb-object-private.hh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-object-private.hh 2016-06-05 23:49:07.940083385 +0200 +@@ -47,19 +47,22 @@ + + /* reference_count */ + +-#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1) +-#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE} ++#define HB_REFERENCE_COUNT_INERT_VALUE -1 ++#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD ++#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)} ++ + struct hb_reference_count_t + { + hb_atomic_int_t ref_count; + +- inline void init (int v) { ref_count = v; } +- inline int inc (void) { return hb_atomic_int_add (const_cast (ref_count), 1); } +- inline int dec (void) { return hb_atomic_int_add (const_cast (ref_count), -1); } +- inline void finish (void) { ref_count = HB_REFERENCE_COUNT_INVALID_VALUE; } +- +- inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; } ++ inline void init (int v) { ref_count.set_unsafe (v); } ++ inline int get_unsafe (void) const { return ref_count.get_unsafe (); } ++ inline int inc (void) { return ref_count.inc (); } ++ inline int dec (void) { return ref_count.dec (); } ++ inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); } + ++ inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; } ++ inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; } + }; + + +@@ -102,7 +105,7 @@ + hb_reference_count_t ref_count; + hb_user_data_array_t user_data; + +-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT} ++#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT} + + private: + ASSERT_POD (); +@@ -117,7 +120,7 @@ + DEBUG_MSG (OBJECT, (void *) obj, + "%s refcount=%d", + function, +- obj ? obj->header.ref_count.ref_count : 0); ++ obj ? obj->header.ref_count.get_unsafe () : 0); + } + + template +@@ -141,7 +144,12 @@ + template + static inline bool hb_object_is_inert (const Type *obj) + { +- return unlikely (obj->header.ref_count.is_invalid ()); ++ return unlikely (obj->header.ref_count.is_inert ()); ++} ++template ++static inline bool hb_object_is_valid (const Type *obj) ++{ ++ return likely (obj->header.ref_count.is_valid ()); + } + template + static inline Type *hb_object_reference (Type *obj) +@@ -149,6 +157,7 @@ + hb_object_trace (obj, HB_FUNC); + if (unlikely (!obj || hb_object_is_inert (obj))) + return obj; ++ assert (hb_object_is_valid (obj)); + obj->header.ref_count.inc (); + return obj; + } +@@ -158,6 +167,7 @@ + hb_object_trace (obj, HB_FUNC); + if (unlikely (!obj || hb_object_is_inert (obj))) + return false; ++ assert (hb_object_is_valid (obj)); + if (obj->header.ref_count.dec () != 1) + return false; + +@@ -174,6 +184,7 @@ + { + if (unlikely (!obj || hb_object_is_inert (obj))) + return false; ++ assert (hb_object_is_valid (obj)); + return obj->header.user_data.set (key, data, destroy, replace); + } + +@@ -183,6 +194,7 @@ + { + if (unlikely (!obj || hb_object_is_inert (obj))) + return NULL; ++ assert (hb_object_is_valid (obj)); + return obj->header.user_data.get (key); + } + +diff -uN gfx/harfbuzz/src_old/hb-open-file-private.hh gfx/harfbuzz/src/hb-open-file-private.hh +--- gfx/harfbuzz/src_old/hb-open-file-private.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-open-file-private.hh 2016-06-05 23:49:09.207076516 +0200 +@@ -53,9 +53,10 @@ + + typedef struct TableRecord + { +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + Tag tag; /* 4-byte identifier. */ +@@ -102,9 +103,10 @@ + } + + public: +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); ++ return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); + } + + protected: +@@ -130,9 +132,10 @@ + inline unsigned int get_face_count (void) const { return table.len; } + inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (table.sanitize (c, this)); ++ return_trace (table.sanitize (c, this)); + } + + protected: +@@ -169,13 +172,14 @@ + } + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false); ++ if (unlikely (!u.header.version.sanitize (c))) return_trace (false); + switch (u.header.version.major) { + case 2: /* version 2 is compatible with version 1 */ +- case 1: return TRACE_RETURN (u.version1.sanitize (c)); +- default:return TRACE_RETURN (true); ++ case 1: return_trace (u.version1.sanitize (c)); ++ default:return_trace (true); + } + } + +@@ -233,16 +237,17 @@ + } + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false); ++ if (unlikely (!u.tag.sanitize (c))) return_trace (false); + switch (u.tag) { + case CFFTag: /* All the non-collection tags */ + case TrueTag: + case Typ1Tag: +- case TrueTypeTag: return TRACE_RETURN (u.fontFace.sanitize (c)); +- case TTCTag: return TRACE_RETURN (u.ttcHeader.sanitize (c)); +- default: return TRACE_RETURN (true); ++ case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); ++ case TTCTag: return_trace (u.ttcHeader.sanitize (c)); ++ default: return_trace (true); + } + } + +diff -uN gfx/harfbuzz/src_old/hb-open-type-private.hh gfx/harfbuzz/src/hb-open-type-private.hh +--- gfx/harfbuzz/src_old/hb-open-type-private.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-open-type-private.hh 2016-06-05 23:49:10.574069085 +0200 +@@ -103,9 +103,6 @@ + static const unsigned int static_size = (size); \ + static const unsigned int min_size = (size) + +-/* Size signifying variable-sized array */ +-#define VAR 1 +- + #define DEFINE_SIZE_UNION(size, _member) \ + DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \ + static const unsigned int min_size = (size) +@@ -154,6 +151,20 @@ + #define Null(Type) Null() + + ++/* ++ * Dispatch ++ */ ++ ++template ++struct hb_dispatch_context_t ++{ ++ static const unsigned int max_debug_depth = MaxDebugDepth; ++ typedef Return return_t; ++ template ++ inline bool may_dispatch (const T *obj, const F *format) { return true; } ++ static return_t no_dispatch_return_value (void) { return Context::default_return_value (); } ++}; ++ + + /* + * Sanitize +@@ -171,18 +182,27 @@ + + /* This limits sanitizing time on really broken fonts. */ + #ifndef HB_SANITIZE_MAX_EDITS +-#define HB_SANITIZE_MAX_EDITS 100 ++#define HB_SANITIZE_MAX_EDITS 32 + #endif + +-struct hb_sanitize_context_t ++struct hb_sanitize_context_t : ++ hb_dispatch_context_t + { ++ inline hb_sanitize_context_t (void) : ++ debug_depth (0), ++ start (NULL), end (NULL), ++ writable (false), edit_count (0), ++ blob (NULL) {} ++ + inline const char *get_name (void) { return "SANITIZE"; } +- static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE; +- typedef bool return_t; ++ template ++ inline bool may_dispatch (const T *obj, const F *format) ++ { return format->sanitize (this); } + template + inline return_t dispatch (const T &obj) { return obj.sanitize (this); } + static return_t default_return_value (void) { return true; } +- bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } ++ static return_t no_dispatch_return_value (void) { return false; } ++ bool stop_sublookup_iteration (const return_t r) const { return !r; } + + inline void init (hb_blob_t *b) + { +@@ -270,9 +290,9 @@ + } + + template +- inline bool try_set (Type *obj, const ValueType &v) { ++ inline bool try_set (const Type *obj, const ValueType &v) { + if (this->may_edit (obj, obj->static_size)) { +- obj->set (v); ++ const_cast (obj)->set (v); + return true; + } + return false; +@@ -292,7 +312,7 @@ + struct Sanitizer + { + static hb_blob_t *sanitize (hb_blob_t *blob) { +- hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}}; ++ hb_sanitize_context_t c[1]; + bool sane; + + /* TODO is_sane() stuff */ +@@ -376,9 +396,9 @@ + + struct hb_serialize_context_t + { +- inline hb_serialize_context_t (void *start, unsigned int size) ++ inline hb_serialize_context_t (void *start_, unsigned int size) + { +- this->start = (char *) start; ++ this->start = (char *) start_; + this->end = this->start + size; + + this->ran_out_of_room = false; +@@ -472,10 +492,10 @@ + return reinterpret_cast (&obj); + } + +- inline void truncate (void *head) ++ inline void truncate (void *new_head) + { +- assert (this->start < head && head <= this->head); +- this->head = (char *) head; ++ assert (this->start < new_head && new_head <= this->head); ++ this->head = (char *) new_head; + } + + unsigned int debug_depth; +@@ -533,6 +553,20 @@ + template struct BEInt; + + template ++struct BEInt ++{ ++ public: ++ inline void set (Type V) ++ { ++ v = V; ++ } ++ inline operator Type (void) const ++ { ++ return v; ++ } ++ private: uint8_t v; ++}; ++template + struct BEInt + { + public: +@@ -546,12 +580,6 @@ + return (v[0] << 8) + + (v[1] ); + } +- inline bool operator == (const BEInt& o) const +- { +- return v[0] == o.v[0] +- && v[1] == o.v[1]; +- } +- inline bool operator != (const BEInt& o) const { return !(*this == o); } + private: uint8_t v[2]; + }; + template +@@ -570,13 +598,6 @@ + + (v[1] << 8) + + (v[2] ); + } +- inline bool operator == (const BEInt& o) const +- { +- return v[0] == o.v[0] +- && v[1] == o.v[1] +- && v[2] == o.v[2]; +- } +- inline bool operator != (const BEInt& o) const { return !(*this == o); } + private: uint8_t v[3]; + }; + template +@@ -597,14 +618,6 @@ + + (v[2] << 8) + + (v[3] ); + } +- inline bool operator == (const BEInt& o) const +- { +- return v[0] == o.v[0] +- && v[1] == o.v[1] +- && v[2] == o.v[2] +- && v[3] == o.v[3]; +- } +- inline bool operator != (const BEInt& o) const { return !(*this == o); } + private: uint8_t v[4]; + }; + +@@ -614,14 +627,21 @@ + { + inline void set (Type i) { v.set (i); } + inline operator Type(void) const { return v; } +- inline bool operator == (const IntType &o) const { return v == o.v; } +- inline bool operator != (const IntType &o) const { return v != o.v; } ++ inline bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } ++ inline bool operator != (const IntType &o) const { return !(*this == o); } + static inline int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } +- inline int cmp (IntType va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } +- inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline int cmp (Type a) const ++ { ++ Type b = v; ++ if (sizeof (Type) < sizeof (int)) ++ return (int) a - (int) b; ++ else ++ return a < b ? -1 : a == b ? 0 : +1; ++ } ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (likely (c->check_struct (this))); ++ return_trace (likely (c->check_struct (this))); + } + protected: + BEInt v; +@@ -629,7 +649,7 @@ + DEFINE_SIZE_STATIC (Size); + }; + +-typedef uint8_t BYTE; /* 8-bit unsigned integer. */ ++typedef IntType BYTE; /* 8-bit unsigned integer. */ + typedef IntType USHORT; /* 16-bit unsigned integer. */ + typedef IntType SHORT; /* 16-bit signed integer. */ + typedef IntType ULONG; /* 32-bit unsigned integer. */ +@@ -646,9 +666,10 @@ + * 1904. The value is represented as a signed 64-bit integer. */ + struct LONGDATETIME + { +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (likely (c->check_struct (this))); ++ return_trace (likely (c->check_struct (this))); + } + protected: + LONG major; +@@ -670,7 +691,10 @@ + DEFINE_NULL_DATA (Tag, " "); + + /* Glyph index number, same as uint16 (length = 16 bits) */ +-typedef USHORT GlyphID; ++struct GlyphID : USHORT { ++ static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); } ++ inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; } ++}; + + /* Script/language-system/feature index */ + struct Index : USHORT { +@@ -719,9 +743,10 @@ + { + inline uint32_t to_int (void) const { return (major << 16) + minor; } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + USHORT major; +@@ -747,33 +772,35 @@ + return StructAtOffset (base, offset); + } + +- inline Type& serialize (hb_serialize_context_t *c, void *base) ++ inline Type& serialize (hb_serialize_context_t *c, const void *base) + { + Type *t = c->start_embed (); + this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ + return *t; + } + +- inline bool sanitize (hb_sanitize_context_t *c, void *base) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); ++ if (unlikely (!c->check_struct (this))) return_trace (false); + unsigned int offset = *this; +- if (unlikely (!offset)) return TRACE_RETURN (true); +- Type &obj = StructAtOffset (base, offset); +- return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); ++ if (unlikely (!offset)) return_trace (true); ++ const Type &obj = StructAtOffset (base, offset); ++ return_trace (likely (obj.sanitize (c)) || neuter (c)); + } + template +- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); ++ if (unlikely (!c->check_struct (this))) return_trace (false); + unsigned int offset = *this; +- if (unlikely (!offset)) return TRACE_RETURN (true); +- Type &obj = StructAtOffset (base, offset); +- return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); ++ if (unlikely (!offset)) return_trace (true); ++ const Type &obj = StructAtOffset (base, offset); ++ return_trace (likely (obj.sanitize (c, user_data)) || neuter (c)); + } + + /* Set the offset to Null */ +- inline bool neuter (hb_sanitize_context_t *c) { ++ inline bool neuter (hb_sanitize_context_t *c) const { + return c->try_set (this, 0); + } + DEFINE_SIZE_STATIC (sizeof(OffsetType)); +@@ -820,10 +847,10 @@ + unsigned int items_len) + { + TRACE_SERIALIZE (this); +- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); ++ if (unlikely (!c->extend_min (*this))) return_trace (false); + len.set (items_len); /* TODO(serialize) Overflow? */ +- if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); +- return TRACE_RETURN (true); ++ if (unlikely (!c->extend (*this))) return_trace (false); ++ return_trace (true); + } + + inline bool serialize (hb_serialize_context_t *c, +@@ -831,16 +858,17 @@ + unsigned int items_len) + { + TRACE_SERIALIZE (this); +- if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false); ++ if (unlikely (!serialize (c, items_len))) return_trace (false); + for (unsigned int i = 0; i < items_len; i++) + array[i] = items[i]; + items.advance (items_len); +- return TRACE_RETURN (true); ++ return_trace (true); + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); ++ if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did +@@ -851,26 +879,28 @@ + */ + (void) (false && array[0].sanitize (c)); + +- return TRACE_RETURN (true); ++ return_trace (true); + } +- inline bool sanitize (hb_sanitize_context_t *c, void *base) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); ++ if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!array[i].sanitize (c, base))) +- return TRACE_RETURN (false); +- return TRACE_RETURN (true); ++ return_trace (false); ++ return_trace (true); + } + template +- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); ++ if (unlikely (!sanitize_shallow (c))) return_trace (false); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (!array[i].sanitize (c, base, user_data))) +- return TRACE_RETURN (false); +- return TRACE_RETURN (true); ++ return_trace (false); ++ return_trace (true); + } + + template +@@ -884,9 +914,10 @@ + } + + private: +- inline bool sanitize_shallow (hb_sanitize_context_t *c) { ++ inline bool sanitize_shallow (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len)); ++ return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len)); + } + + public: +@@ -910,14 +941,16 @@ + return this+this->array[i]; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (OffsetArrayOf::sanitize (c, this)); ++ return_trace (OffsetArrayOf::sanitize (c, this)); + } + template +- inline bool sanitize (hb_sanitize_context_t *c, T user_data) { ++ inline bool sanitize (hb_sanitize_context_t *c, T user_data) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (OffsetArrayOf::sanitize (c, this, user_data)); ++ return_trace (OffsetArrayOf::sanitize (c, this, user_data)); + } + }; + +@@ -939,24 +972,26 @@ + unsigned int items_len) + { + TRACE_SERIALIZE (this); +- if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); ++ if (unlikely (!c->extend_min (*this))) return_trace (false); + len.set (items_len); /* TODO(serialize) Overflow? */ +- if (unlikely (!items_len)) return TRACE_RETURN (true); +- if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); ++ if (unlikely (!items_len)) return_trace (true); ++ if (unlikely (!c->extend (*this))) return_trace (false); + for (unsigned int i = 0; i < items_len - 1; i++) + array[i] = items[i]; + items.advance (items_len - 1); +- return TRACE_RETURN (true); ++ return_trace (true); + } + +- inline bool sanitize_shallow (hb_sanitize_context_t *c) { ++ inline bool sanitize_shallow (hb_sanitize_context_t *c) const ++ { + return c->check_struct (this) + && c->check_array (this, Type::static_size, len); + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); ++ if (unlikely (!sanitize_shallow (c))) return_trace (false); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did +@@ -967,7 +1002,7 @@ + */ + (void) (false && array[0].sanitize (c)); + +- return TRACE_RETURN (true); ++ return_trace (true); + } + + LenType len; +diff -uN gfx/harfbuzz/src_old/hb-ot-cmap-table.hh gfx/harfbuzz/src/hb-ot-cmap-table.hh +--- gfx/harfbuzz/src_old/hb-ot-cmap-table.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-cmap-table.hh 2016-06-05 23:49:11.982061464 +0200 +@@ -51,9 +51,10 @@ + return true; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + protected: +@@ -125,11 +126,11 @@ + return true; + } + +- inline bool sanitize (hb_sanitize_context_t *c) ++ inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) +- return TRACE_RETURN (false); ++ return_trace (false); + + if (unlikely (!c->check_range (this, length))) + { +@@ -140,10 +141,10 @@ + (uintptr_t) (c->end - + (char *) this)); + if (!c->try_set (&length, new_length)) +- return TRACE_RETURN (false); ++ return_trace (false); + } + +- return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length); ++ return_trace (16 + 4 * (unsigned int) segCountX2 <= length); + } + + protected: +@@ -183,9 +184,10 @@ + return 0; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + private: +@@ -210,9 +212,10 @@ + return true; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c)); ++ return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); + } + + protected: +@@ -242,9 +245,10 @@ + return true; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c)); ++ return_trace (c->check_struct (this) && groups.sanitize (c)); + } + + protected: +@@ -288,9 +292,10 @@ + return 0; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + UINT24 startUnicodeValue; /* First value in this range. */ +@@ -309,9 +314,10 @@ + return unicodeValue.cmp (codepoint); + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + UINT24 unicodeValue; /* Base Unicode value of the UVS */ +@@ -348,11 +354,12 @@ + return varSelector.cmp (variation_selector); + } + +- inline bool sanitize (hb_sanitize_context_t *c, void *base) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && +- defaultUVS.sanitize (c, base) && +- nonDefaultUVS.sanitize (c, base)); ++ return_trace (c->check_struct (this) && ++ defaultUVS.sanitize (c, base) && ++ nonDefaultUVS.sanitize (c, base)); + } + + UINT24 varSelector; /* Variation selector. */ +@@ -373,10 +380,11 @@ + return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && +- record.sanitize (c, this)); ++ return_trace (c->check_struct (this) && ++ record.sanitize (c, this)); + } + + protected: +@@ -418,18 +426,19 @@ + } + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- if (!u.format.sanitize (c)) return TRACE_RETURN (false); ++ if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { +- case 0: return TRACE_RETURN (u.format0 .sanitize (c)); +- case 4: return TRACE_RETURN (u.format4 .sanitize (c)); +- case 6: return TRACE_RETURN (u.format6 .sanitize (c)); +- case 10: return TRACE_RETURN (u.format10.sanitize (c)); +- case 12: return TRACE_RETURN (u.format12.sanitize (c)); +- case 13: return TRACE_RETURN (u.format13.sanitize (c)); +- case 14: return TRACE_RETURN (u.format14.sanitize (c)); +- default:return TRACE_RETURN (true); ++ case 0: return_trace (u.format0 .sanitize (c)); ++ case 4: return_trace (u.format4 .sanitize (c)); ++ case 6: return_trace (u.format6 .sanitize (c)); ++ case 10: return_trace (u.format10.sanitize (c)); ++ case 12: return_trace (u.format12.sanitize (c)); ++ case 13: return_trace (u.format13.sanitize (c)); ++ case 14: return_trace (u.format14.sanitize (c)); ++ default:return_trace (true); + } + } + +@@ -461,10 +470,11 @@ + return 0; + } + +- inline bool sanitize (hb_sanitize_context_t *c, void *base) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && +- subtable.sanitize (c, base)); ++ return_trace (c->check_struct (this) && ++ subtable.sanitize (c, base)); + } + + USHORT platformID; /* Platform ID. */ +@@ -496,11 +506,12 @@ + return &(this+encodingRecord[result].subtable); + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && +- likely (version == 0) && +- encodingRecord.sanitize (c, this)); ++ return_trace (c->check_struct (this) && ++ likely (version == 0) && ++ encodingRecord.sanitize (c, this)); + } + + USHORT version; /* Table version number (0). */ +diff -uN gfx/harfbuzz/src_old/hb-ot-font.cc gfx/harfbuzz/src/hb-ot-font.cc +--- gfx/harfbuzz/src_old/hb-ot-font.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-font.cc 2016-06-05 23:49:13.433053614 +0200 +@@ -31,8 +31,11 @@ + #include "hb-font-private.hh" + + #include "hb-ot-cmap-table.hh" ++#include "hb-ot-glyf-table.hh" ++#include "hb-ot-head-table.hh" + #include "hb-ot-hhea-table.hh" + #include "hb-ot-hmtx-table.hh" ++#include "hb-ot-os2-table.hh" + + + struct hb_ot_face_metrics_accelerator_t +@@ -40,24 +43,58 @@ + unsigned int num_metrics; + unsigned int num_advances; + unsigned int default_advance; ++ unsigned short ascender; ++ unsigned short descender; ++ unsigned short line_gap; ++ + const OT::_mtx *table; + hb_blob_t *blob; + + inline void init (hb_face_t *face, +- hb_tag_t _hea_tag, hb_tag_t _mtx_tag, +- unsigned int default_advance) ++ hb_tag_t _hea_tag, ++ hb_tag_t _mtx_tag, ++ hb_tag_t os2_tag) + { +- this->default_advance = default_advance; +- this->num_metrics = face->get_num_glyphs (); ++ this->default_advance = face->get_upem (); ++ ++ bool got_font_extents = false; ++ if (os2_tag) ++ { ++ hb_blob_t *os2_blob = OT::Sanitizer::sanitize (face->reference_table (os2_tag)); ++ const OT::os2 *os2 = OT::Sanitizer::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::sanitize (face->reference_table (_hea_tag)); + const OT::_hea *_hea = OT::Sanitizer::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::sanitize (face->reference_table (_mtx_tag)); +- if (unlikely (!this->num_advances || +- 2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob))) ++ ++ /* Cap num_metrics() and num_advances() based on table length. */ ++ unsigned int len = hb_blob_get_length (this->blob); ++ if (unlikely (this->num_advances * 4 > len)) ++ this->num_advances = len / 4; ++ this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2; ++ ++ /* We MUST set num_metrics to zero if num_advances is zero. ++ * Our get_advance() depends on that. */ ++ if (unlikely (!this->num_advances)) + { + this->num_metrics = this->num_advances = 0; + hb_blob_destroy (this->blob); +@@ -76,8 +113,8 @@ + if (unlikely (glyph >= this->num_metrics)) + { + /* If this->num_metrics is zero, it means we don't have the metrics table +- * for this direction: return one EM. Otherwise, it means that the glyph +- * index is out of bound: return zero. */ ++ * for this direction: return default advance. Otherwise, it means that the ++ * glyph index is out of bound: return zero. */ + if (this->num_metrics) + return 0; + else +@@ -91,6 +128,79 @@ + } + }; + ++struct hb_ot_face_glyf_accelerator_t ++{ ++ bool short_offset; ++ unsigned int num_glyphs; ++ const OT::loca *loca; ++ const OT::glyf *glyf; ++ hb_blob_t *loca_blob; ++ hb_blob_t *glyf_blob; ++ unsigned int glyf_len; ++ ++ inline void init (hb_face_t *face) ++ { ++ hb_blob_t *head_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_head)); ++ const OT::head *head = OT::Sanitizer::lock_instance (head_blob); ++ if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0) ++ { ++ /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ ++ hb_blob_destroy (head_blob); ++ return; ++ } ++ this->short_offset = 0 == head->indexToLocFormat; ++ hb_blob_destroy (head_blob); ++ ++ this->loca_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_loca)); ++ this->loca = OT::Sanitizer::lock_instance (this->loca_blob); ++ this->glyf_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_glyf)); ++ this->glyf = OT::Sanitizer::lock_instance (this->glyf_blob); ++ ++ this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1; ++ this->glyf_len = hb_blob_get_length (this->glyf_blob); ++ } ++ ++ inline void fini (void) ++ { ++ hb_blob_destroy (this->loca_blob); ++ hb_blob_destroy (this->glyf_blob); ++ } ++ ++ inline bool get_extents (hb_codepoint_t glyph, ++ hb_glyph_extents_t *extents) const ++ { ++ if (unlikely (glyph >= this->num_glyphs)) ++ return false; ++ ++ unsigned int start_offset, end_offset; ++ if (this->short_offset) ++ { ++ start_offset = 2 * this->loca->u.shortsZ[glyph]; ++ end_offset = 2 * this->loca->u.shortsZ[glyph + 1]; ++ } ++ else ++ { ++ start_offset = this->loca->u.longsZ[glyph]; ++ end_offset = this->loca->u.longsZ[glyph + 1]; ++ } ++ ++ if (start_offset > end_offset || end_offset > this->glyf_len) ++ return false; ++ ++ if (end_offset - start_offset < OT::glyfGlyphHeader::static_size) ++ return true; /* Empty glyph; zero extents. */ ++ ++ const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset (this->glyf, start_offset); ++ ++ extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); ++ extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); ++ extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; ++ extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; ++ ++ return true; ++ } ++}; ++ + struct hb_ot_face_cmap_accelerator_t + { + const OT::CmapSubtable *table; +@@ -114,6 +224,7 @@ + if (!subtable) subtable = cmap->find_subtable (0, 2); + if (!subtable) subtable = cmap->find_subtable (0, 1); + if (!subtable) subtable = cmap->find_subtable (0, 0); ++ if (!subtable) subtable = cmap->find_subtable (3, 0); + /* Meh. */ + if (!subtable) subtable = &OT::Null(OT::CmapSubtable); + +@@ -157,23 +268,22 @@ + hb_ot_face_cmap_accelerator_t cmap; + hb_ot_face_metrics_accelerator_t h_metrics; + hb_ot_face_metrics_accelerator_t v_metrics; ++ hb_ot_face_glyf_accelerator_t glyf; + }; + + + static hb_ot_font_t * +-_hb_ot_font_create (hb_font_t *font) ++_hb_ot_font_create (hb_face_t *face) + { + hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); +- hb_face_t *face = font->face; + + if (unlikely (!ot_font)) + return NULL; + +- unsigned int upem = face->get_upem (); +- + ot_font->cmap.init (face); +- ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1); +- ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */ ++ ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2); ++ ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */ ++ ot_font->glyf.init (face); + + return ot_font; + } +@@ -184,6 +294,7 @@ + ot_font->cmap.fini (); + ot_font->h_metrics.fini (); + ot_font->v_metrics.fini (); ++ ot_font->glyf.fini (); + + free (ot_font); + } +@@ -219,53 +330,7 @@ + void *user_data HB_UNUSED) + { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; +- return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph)); +-} +- +-static hb_bool_t +-hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED, +- void *font_data HB_UNUSED, +- hb_codepoint_t glyph HB_UNUSED, +- hb_position_t *x HB_UNUSED, +- hb_position_t *y HB_UNUSED, +- void *user_data HB_UNUSED) +-{ +- /* We always work in the horizontal coordinates. */ +- return true; +-} +- +-static hb_bool_t +-hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED, +- void *font_data, +- hb_codepoint_t glyph, +- hb_position_t *x, +- hb_position_t *y, +- void *user_data HB_UNUSED) +-{ +- /* TODO */ +- return false; +-} +- +-static hb_position_t +-hb_ot_get_glyph_h_kerning (hb_font_t *font, +- void *font_data, +- hb_codepoint_t left_glyph, +- hb_codepoint_t right_glyph, +- void *user_data HB_UNUSED) +-{ +- /* TODO */ +- return 0; +-} +- +-static hb_position_t +-hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, +- void *font_data HB_UNUSED, +- hb_codepoint_t top_glyph HB_UNUSED, +- hb_codepoint_t bottom_glyph HB_UNUSED, +- void *user_data HB_UNUSED) +-{ +- /* OpenType doesn't have vertical-kerning other than GPOS. */ +- return 0; ++ return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph)); + } + + static hb_bool_t +@@ -275,69 +340,100 @@ + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) + { +- /* TODO */ +- return false; ++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; ++ bool ret = ot_font->glyf.get_extents (glyph, extents); ++ extents->x_bearing = font->em_scale_x (extents->x_bearing); ++ extents->y_bearing = font->em_scale_y (extents->y_bearing); ++ extents->width = font->em_scale_x (extents->width); ++ extents->height = font->em_scale_y (extents->height); ++ return ret; + } + + static hb_bool_t +-hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED, +- void *font_data, +- hb_codepoint_t glyph, +- unsigned int point_index, +- hb_position_t *x, +- hb_position_t *y, +- void *user_data HB_UNUSED) ++hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED, ++ void *font_data, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) + { +- /* TODO */ +- return false; ++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; ++ metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender); ++ metrics->descender = font->em_scale_y (ot_font->h_metrics.descender); ++ metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap); ++ return true; + } + + static hb_bool_t +-hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, +- void *font_data, +- hb_codepoint_t glyph, +- char *name, unsigned int size, +- void *user_data HB_UNUSED) ++hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED, ++ void *font_data, ++ hb_font_extents_t *metrics, ++ void *user_data HB_UNUSED) + { +- /* TODO */ +- return false; ++ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; ++ metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender); ++ metrics->descender = font->em_scale_x (ot_font->v_metrics.descender); ++ metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap); ++ return true; + } + +-static hb_bool_t +-hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, +- void *font_data, +- const char *name, int len, /* -1 means nul-terminated */ +- hb_codepoint_t *glyph, +- void *user_data HB_UNUSED) ++static hb_font_funcs_t *static_ot_funcs = NULL; ++ ++#ifdef HB_USE_ATEXIT ++static ++void free_static_ot_funcs (void) + { +- /* TODO */ +- return false; ++ hb_font_funcs_destroy (static_ot_funcs); + } +- ++#endif + + static hb_font_funcs_t * + _hb_ot_get_font_funcs (void) + { +- static const hb_font_funcs_t ot_ffuncs = { +- HB_OBJECT_HEADER_STATIC, ++retry: ++ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); + +- true, /* immutable */ ++ if (unlikely (!funcs)) ++ { ++ funcs = hb_font_funcs_create (); + +- { +-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name, +- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +-#undef HB_FONT_FUNC_IMPLEMENT ++ hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL); ++ hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL); ++ hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL); ++ hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL); ++ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL); ++ //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL); ++ //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL); ++ //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO ++ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL); ++ hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL); ++ //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO ++ //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO ++ //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO ++ ++ hb_font_funcs_make_immutable (funcs); ++ ++ if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) { ++ hb_font_funcs_destroy (funcs); ++ goto retry; + } ++ ++#ifdef HB_USE_ATEXIT ++ atexit (free_static_ot_funcs); /* First person registers atexit() callback. */ ++#endif + }; + +- return const_cast (&ot_ffuncs); ++ return funcs; + } + + ++/** ++ * hb_ot_font_set_funcs: ++ * ++ * Since: 0.9.28 ++ **/ + void + hb_ot_font_set_funcs (hb_font_t *font) + { +- hb_ot_font_t *ot_font = _hb_ot_font_create (font); ++ hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); + if (unlikely (!ot_font)) + return; + +diff -uN gfx/harfbuzz/src_old/hb-ot-font.h gfx/harfbuzz/src/hb-ot-font.h +--- gfx/harfbuzz/src_old/hb-ot-font.h 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-font.h 2016-06-05 23:49:14.679046863 +0200 +@@ -24,6 +24,10 @@ + * Google Author(s): Behdad Esfahbod, Roozbeh Pournader + */ + ++#ifndef HB_OT_H_IN ++#error "Include instead." ++#endif ++ + #ifndef HB_OT_FONT_H + #define HB_OT_FONT_H + +@@ -32,7 +36,7 @@ + HB_BEGIN_DECLS + + +-void ++HB_EXTERN void + hb_ot_font_set_funcs (hb_font_t *font); + + +diff -uN gfx/harfbuzz/src_old/hb-ot-glyf-table.hh gfx/harfbuzz/src/hb-ot-glyf-table.hh +--- gfx/harfbuzz/src_old/hb-ot-glyf-table.hh 1970-01-01 01:00:00.000000000 +0100 ++++ gfx/harfbuzz/src/hb-ot-glyf-table.hh 2016-06-05 23:49:15.900040281 +0200 +@@ -0,0 +1,104 @@ ++/* ++ * Copyright © 2015 Google, Inc. ++ * ++ * This is part of HarfBuzz, a text shaping library. ++ * ++ * Permission is hereby granted, without written agreement and without ++ * license or royalty fees, to use, copy, modify, and distribute this ++ * software and its documentation for any purpose, provided that the ++ * above copyright notice and the following two paragraphs appear in ++ * all copies of this software. ++ * ++ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR ++ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ++ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN ++ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, ++ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND ++ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ++ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO ++ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. ++ * ++ * Google Author(s): Behdad Esfahbod ++ */ ++ ++#ifndef HB_OT_GLYF_TABLE_HH ++#define HB_OT_GLYF_TABLE_HH ++ ++#include "hb-open-type-private.hh" ++ ++ ++namespace OT { ++ ++ ++/* ++ * loca -- Index to Location ++ */ ++ ++#define HB_OT_TAG_loca HB_TAG('l','o','c','a') ++ ++ ++struct loca ++{ ++ static const hb_tag_t tableTag = HB_OT_TAG_loca; ++ ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { ++ TRACE_SANITIZE (this); ++ return_trace (true); ++ } ++ ++ public: ++ union { ++ USHORT shortsZ[VAR]; /* Location offset divided by 2. */ ++ ULONG longsZ[VAR]; /* Location offset. */ ++ } u; ++ DEFINE_SIZE_ARRAY (0, u.longsZ); ++}; ++ ++ ++/* ++ * glyf -- TrueType Glyph Data ++ */ ++ ++#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') ++ ++ ++struct glyf ++{ ++ static const hb_tag_t tableTag = HB_OT_TAG_glyf; ++ ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { ++ TRACE_SANITIZE (this); ++ /* We don't check for anything specific here. The users of the ++ * struct do all the hard work... */ ++ return_trace (true); ++ } ++ ++ public: ++ BYTE dataX[VAR]; /* Glyphs data. */ ++ ++ DEFINE_SIZE_ARRAY (0, dataX); ++}; ++ ++struct glyfGlyphHeader ++{ ++ SHORT numberOfContours; /* If the number of contours is ++ * greater than or equal to zero, ++ * this is a simple glyph; if negative, ++ * this is a composite glyph. */ ++ SHORT xMin; /* Minimum x for coordinate data. */ ++ SHORT yMin; /* Minimum y for coordinate data. */ ++ SHORT xMax; /* Maximum x for coordinate data. */ ++ SHORT yMax; /* Maximum y for coordinate data. */ ++ ++ DEFINE_SIZE_STATIC (10); ++}; ++ ++} /* namespace OT */ ++ ++ ++#endif /* HB_OT_GLYF_TABLE_HH */ +diff -uN gfx/harfbuzz/src_old/hb-ot-head-table.hh gfx/harfbuzz/src/hb-ot-head-table.hh +--- gfx/harfbuzz/src_old/hb-ot-head-table.hh 2016-05-10 22:26:55.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-head-table.hh 2016-06-05 23:49:17.080033892 +0200 +@@ -45,15 +45,19 @@ + { + static const hb_tag_t tableTag = HB_OT_TAG_head; + +- inline unsigned int get_upem (void) const { ++ inline unsigned int get_upem (void) const ++ { + unsigned int upem = unitsPerEm; + /* If no valid head table found, assume 1000, which matches typical Type1 usage. */ + return 16 <= upem && upem <= 16384 ? upem : 1000; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); ++ return_trace (c->check_struct (this) && ++ version.major == 1 && ++ magicNumber == 0x5F0F3CF5u); + } + + protected: +@@ -136,9 +140,10 @@ + * 2: Like 1 but also contains neutrals; + * -1: Only strongly right to left; + * -2: Like -1 but also contains neutrals. */ ++ public: + SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */ + SHORT glyphDataFormat; /* 0 for current format. */ +- public: ++ + DEFINE_SIZE_STATIC (54); + }; + +diff -uN gfx/harfbuzz/src_old/hb-ot-hhea-table.hh gfx/harfbuzz/src/hb-ot-hhea-table.hh +--- gfx/harfbuzz/src_old/hb-ot-hhea-table.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-hhea-table.hh 2016-06-05 23:49:18.320027217 +0200 +@@ -49,9 +49,10 @@ + static const hb_tag_t hheaTag = HB_OT_TAG_hhea; + static const hb_tag_t vheaTag = HB_OT_TAG_vhea; + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); ++ return_trace (c->check_struct (this) && likely (version.major == 1)); + } + + public: +diff -uN gfx/harfbuzz/src_old/hb-ot-hmtx-table.hh gfx/harfbuzz/src/hb-ot-hmtx-table.hh +--- gfx/harfbuzz/src_old/hb-ot-hmtx-table.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-hmtx-table.hh 2016-06-05 23:49:19.601020309 +0200 +@@ -57,11 +57,12 @@ + static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx; + static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx; + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); + /* We don't check for anything specific here. The users of the + * struct do all the hard work... */ +- return TRACE_RETURN (true); ++ return_trace (true); + } + + public: +diff -uN gfx/harfbuzz/src_old/hb-ot-layout.cc gfx/harfbuzz/src/hb-ot-layout.cc +--- gfx/harfbuzz/src_old/hb-ot-layout.cc 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-layout.cc 2016-06-05 23:49:31.325957413 +0200 +@@ -28,6 +28,7 @@ + * Google Author(s): Behdad Esfahbod + */ + ++#include "hb-open-type-private.hh" + #include "hb-ot-layout-private.hh" + + #include "hb-ot-layout-gdef-table.hh" +@@ -84,9 +85,9 @@ + _hb_ot_layout_destroy (hb_ot_layout_t *layout) + { + for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) +- layout->gsub_accels[i].fini (layout->gsub->get_lookup (i)); ++ layout->gsub_accels[i].fini (); + for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) +- layout->gpos_accels[i].fini (layout->gpos->get_lookup (i)); ++ layout->gpos_accels[i].fini (); + + free (layout->gsub_accels); + free (layout->gpos_accels); +@@ -128,6 +129,11 @@ + return _get_gdef (face).has_glyph_classes (); + } + ++/** ++ * hb_ot_layout_get_glyph_class: ++ * ++ * Since: 0.9.7 ++ **/ + hb_ot_layout_glyph_class_t + hb_ot_layout_get_glyph_class (hb_face_t *face, + hb_codepoint_t glyph) +@@ -135,6 +141,11 @@ + return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); + } + ++/** ++ * hb_ot_layout_get_glyphs_in_class: ++ * ++ * Since: 0.9.7 ++ **/ + void + hb_ot_layout_get_glyphs_in_class (hb_face_t *face, + hb_ot_layout_glyph_class_t klass, +@@ -285,6 +296,28 @@ + return g.get_feature_tags (start_offset, feature_count, feature_tags); + } + ++hb_bool_t ++hb_ot_layout_table_find_feature (hb_face_t *face, ++ hb_tag_t table_tag, ++ hb_tag_t feature_tag, ++ unsigned int *feature_index) ++{ ++ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX); ++ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); ++ ++ unsigned int num_features = g.get_feature_count (); ++ for (unsigned int i = 0; i < num_features; i++) ++ { ++ if (feature_tag == g.get_feature_tag (i)) { ++ if (feature_index) *feature_index = i; ++ return true; ++ } ++ } ++ ++ if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX; ++ return false; ++} ++ + + unsigned int + hb_ot_layout_script_get_language_tags (hb_face_t *face, +@@ -335,6 +368,11 @@ + NULL); + } + ++/** ++ * hb_ot_layout_language_get_required_feature: ++ * ++ * Since: 0.9.30 ++ **/ + hb_bool_t + hb_ot_layout_language_get_required_feature (hb_face_t *face, + hb_tag_t table_tag, +@@ -419,6 +457,11 @@ + return false; + } + ++/** ++ * hb_ot_layout_feature_get_lookups: ++ * ++ * Since: 0.9.7 ++ **/ + unsigned int + hb_ot_layout_feature_get_lookups (hb_face_t *face, + hb_tag_t table_tag, +@@ -433,6 +476,11 @@ + return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); + } + ++/** ++ * hb_ot_layout_table_get_lookup_count: ++ * ++ * Since: 0.9.22 ++ **/ + unsigned int + hb_ot_layout_table_get_lookup_count (hb_face_t *face, + hb_tag_t table_tag) +@@ -590,6 +638,11 @@ + } + } + ++/** ++ * hb_ot_layout_collect_lookups: ++ * ++ * Since: 0.9.8 ++ **/ + void + hb_ot_layout_collect_lookups (hb_face_t *face, + hb_tag_t table_tag, +@@ -631,6 +684,11 @@ + } + } + ++/** ++ * hb_ot_layout_lookup_collect_glyphs: ++ * ++ * Since: 0.9.7 ++ **/ + void + hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, + hb_tag_t table_tag, +@@ -676,6 +734,11 @@ + return &_get_gsub (face) != &OT::Null(OT::GSUB); + } + ++/** ++ * hb_ot_layout_lookup_would_substitute: ++ * ++ * Since: 0.9.7 ++ **/ + hb_bool_t + hb_ot_layout_lookup_would_substitute (hb_face_t *face, + unsigned int lookup_index, +@@ -695,11 +758,11 @@ + hb_bool_t zero_context) + { + if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false; +- OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context); ++ OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); + + const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); + +- return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest); ++ return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]); + } + + void +@@ -714,6 +777,11 @@ + OT::GSUB::substitute_finish (font, buffer); + } + ++/** ++ * hb_ot_layout_lookup_substitute_closure: ++ * ++ * Since: 0.9.7 ++ **/ + void + hb_ot_layout_lookup_substitute_closure (hb_face_t *face, + unsigned int lookup_index, +@@ -748,6 +816,11 @@ + OT::GPOS::position_finish (font, buffer); + } + ++/** ++ * hb_ot_layout_get_size_params: ++ * ++ * Since: 0.9.10 ++ **/ + hb_bool_t + hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ +@@ -829,28 +902,82 @@ + }; + + +-template +-static inline bool apply_once (OT::hb_apply_context_t *c, +- const Lookup &lookup) ++template ++static inline bool ++apply_forward (OT::hb_apply_context_t *c, ++ const Obj &obj, ++ const hb_ot_layout_lookup_accelerator_t &accel) + { +- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) +- return false; +- return lookup.dispatch (c); ++ bool ret = false; ++ hb_buffer_t *buffer = c->buffer; ++ while (buffer->idx < buffer->len && !buffer->in_error) ++ { ++ if (accel.may_have (buffer->cur().codepoint) && ++ (buffer->cur().mask & c->lookup_mask) && ++ c->check_glyph_property (&buffer->cur(), c->lookup_props) && ++ obj.apply (c)) ++ ret = true; ++ else ++ buffer->next_glyph (); ++ } ++ return ret; + } + +-template ++template + static inline bool ++apply_backward (OT::hb_apply_context_t *c, ++ const Obj &obj, ++ const hb_ot_layout_lookup_accelerator_t &accel) ++{ ++ bool ret = false; ++ hb_buffer_t *buffer = c->buffer; ++ do ++ { ++ if (accel.may_have (buffer->cur().codepoint) && ++ (buffer->cur().mask & c->lookup_mask) && ++ c->check_glyph_property (&buffer->cur(), c->lookup_props) && ++ obj.apply (c)) ++ ret = true; ++ /* The reverse lookup doesn't "advance" cursor (for good reason). */ ++ buffer->idx--; ++ ++ } ++ while ((int) buffer->idx >= 0); ++ return ret; ++} ++ ++struct hb_apply_forward_context_t : ++ OT::hb_dispatch_context_t ++{ ++ inline const char *get_name (void) { return "APPLY_FWD"; } ++ template ++ inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); } ++ static return_t default_return_value (void) { return false; } ++ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; } ++ ++ hb_apply_forward_context_t (OT::hb_apply_context_t *c_, ++ const hb_ot_layout_lookup_accelerator_t &accel_) : ++ c (c_), ++ accel (accel_), ++ debug_depth (0) {} ++ ++ OT::hb_apply_context_t *c; ++ const hb_ot_layout_lookup_accelerator_t &accel; ++ unsigned int debug_depth; ++}; ++ ++template ++static inline void + apply_string (OT::hb_apply_context_t *c, + const typename Proxy::Lookup &lookup, + const hb_ot_layout_lookup_accelerator_t &accel) + { +- bool ret = false; + hb_buffer_t *buffer = c->buffer; + + if (unlikely (!buffer->len || !c->lookup_mask)) +- return false; ++ return; + +- c->set_lookup (lookup); ++ c->set_lookup_props (lookup.get_props ()); + + if (likely (!lookup.is_reverse ())) + { +@@ -859,21 +986,20 @@ + buffer->clear_output (); + buffer->idx = 0; + +- while (buffer->idx < buffer->len) ++ bool ret; ++ if (lookup.get_subtable_count () == 1) + { +- if (accel.digest.may_have (buffer->cur().codepoint) && +- (buffer->cur().mask & c->lookup_mask) && +- apply_once (c, lookup)) +- ret = true; +- else +- buffer->next_glyph (); ++ hb_apply_forward_context_t c_forward (c, accel); ++ ret = lookup.dispatch (&c_forward); + } ++ else ++ ret = apply_forward (c, lookup, accel); + if (ret) + { + if (!Proxy::inplace) + buffer->swap_buffers (); + else +- assert (!buffer->has_separate_output ()); ++ assert (!buffer->has_separate_output ()); + } + } + else +@@ -882,20 +1008,9 @@ + if (Proxy::table_index == 0) + buffer->remove_output (); + buffer->idx = buffer->len - 1; +- do +- { +- if (accel.digest.may_have (buffer->cur().codepoint) && +- (buffer->cur().mask & c->lookup_mask) && +- apply_once (c, lookup)) +- ret = true; +- /* The reverse lookup doesn't "advance" cursor (for good reason). */ +- buffer->idx--; + +- } +- while ((int) buffer->idx >= 0); ++ apply_backward (c, lookup, accel); + } +- +- return ret; + } + + template +@@ -914,11 +1029,14 @@ + for (; i < stage->last_lookup; i++) + { + unsigned int lookup_index = lookups[table_index][i].index; ++ if (!buffer->message (font, "start lookup %d", lookup_index)) continue; ++ c.set_lookup_index (lookup_index); + c.set_lookup_mask (lookups[table_index][i].mask); + c.set_auto_zwj (lookups[table_index][i].auto_zwj); + apply_string (&c, + proxy.table.get_lookup (lookup_index), + proxy.accels[lookup_index]); ++ (void) buffer->message (font, "end lookup %d", lookup_index); + } + + if (stage->pause_func) +diff -uN gfx/harfbuzz/src_old/hb-ot-layout-common-private.hh gfx/harfbuzz/src/hb-ot-layout-common-private.hh +--- gfx/harfbuzz/src_old/hb-ot-layout-common-private.hh 2016-05-10 22:26:56.000000000 +0200 ++++ gfx/harfbuzz/src/hb-ot-layout-common-private.hh 2016-06-05 23:49:21.127012094 +0200 +@@ -34,12 +34,24 @@ + #include "hb-set-private.hh" + + ++#ifndef HB_MAX_NESTING_LEVEL ++#define HB_MAX_NESTING_LEVEL 6 ++#endif ++#ifndef HB_MAX_CONTEXT_LENGTH ++#define HB_MAX_CONTEXT_LENGTH 64 ++#endif ++ ++ + namespace OT { + + ++#define TRACE_DISPATCH(this, format) \ ++ hb_auto_trace_t trace \ ++ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ++ "format %d", (int) format); ++ ++ + #define NOT_COVERED ((unsigned int) -1) +-#define MAX_NESTING_LEVEL 8 +-#define MAX_CONTEXT_LENGTH 64 + + + +@@ -63,12 +75,13 @@ + + struct sanitize_closure_t { + hb_tag_t tag; +- void *list_base; ++ const void *list_base; + }; +- inline bool sanitize (hb_sanitize_context_t *c, void *base) { ++ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const ++ { + TRACE_SANITIZE (this); + const sanitize_closure_t closure = {tag, base}; +- return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure)); ++ return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); + } + + Tag tag; /* 4-byte Tag identifier */ +@@ -121,9 +134,10 @@ + inline const Type& operator [] (unsigned int i) const + { return this+RecordArrayOf::operator [](i).offset; } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (RecordArrayOf::sanitize (c, this)); ++ return_trace (RecordArrayOf::sanitize (c, this)); + } + }; + +@@ -134,9 +148,10 @@ + return g < start ? -1 : g <= end ? 0 : +1 ; + } + +- inline bool sanitize (hb_sanitize_context_t *c) { ++ inline bool sanitize (hb_sanitize_context_t *c) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this)); ++ return_trace (c->check_struct (this)); + } + + inline bool intersects (const hb_set_t *glyphs) const { +@@ -199,9 +214,10 @@ + } + + inline bool sanitize (hb_sanitize_context_t *c, +- const Record::sanitize_closure_t * = NULL) { ++ const Record::sanitize_closure_t * = NULL) const ++ { + TRACE_SANITIZE (this); +- return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); ++ return_trace (c->check_struct (this) && featureIndex.sanitize (c)); + } + + Offset<> lookupOrderZ; /* = Null (reserved for an offset to a +@@ -238,9 +254,10 @@ + inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } + + inline bool sanitize (hb_sanitize_context_t *c, +- const Record