summaryrefslogtreecommitdiffstats
path: root/third_party/harfbuzz
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-07 00:44:49 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-07 00:44:49 +0000
commit83f6e08f4c56ef411ad1da5f3bfd4711ec94b052 (patch)
tree6bf8e871963cfc1ab8bf6190dceed5b9631cf8ee /third_party/harfbuzz
parentd5c0e0e416a67e7e8dd98745cdf1bdc7de20517c (diff)
downloadchromium_src-83f6e08f4c56ef411ad1da5f3bfd4711ec94b052.zip
chromium_src-83f6e08f4c56ef411ad1da5f3bfd4711ec94b052.tar.gz
chromium_src-83f6e08f4c56ef411ad1da5f3bfd4711ec94b052.tar.bz2
Add Harfbuzz to third_party and Skia support for such.
Harfbuzz is an open source library which is a unification of the Qt and Pango shaping engines. We'll be using it on Chromium Linux to perform complex text shaping. Additionally, we add support for Harfbuzz into Skia, guarded by SKIA_HARFBUZZ. http://codereview.chromium.org/63035/show git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13214 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/harfbuzz')
-rw-r--r--third_party/harfbuzz/.gitignore20
-rw-r--r--third_party/harfbuzz/AUTHORS6
-rw-r--r--third_party/harfbuzz/COPYING24
-rw-r--r--third_party/harfbuzz/ChangeLog0
-rw-r--r--third_party/harfbuzz/Makefile.am2
-rw-r--r--third_party/harfbuzz/NEWS0
-rw-r--r--third_party/harfbuzz/README7
-rw-r--r--third_party/harfbuzz/README.google32
-rwxr-xr-xthird_party/harfbuzz/autogen.sh116
-rw-r--r--third_party/harfbuzz/config.h60
-rw-r--r--third_party/harfbuzz/configure.ac54
-rw-r--r--third_party/harfbuzz/contrib/README9
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-freetype.c149
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-freetype.h9
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-unicode-glib.c169
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-unicode-tables.c84
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-unicode.c264
-rw-r--r--third_party/harfbuzz/contrib/harfbuzz-unicode.h54
-rw-r--r--third_party/harfbuzz/contrib/tables/DerivedCombiningClass.txt1881
-rw-r--r--third_party/harfbuzz/contrib/tables/DerivedGeneralCategory.txt3072
-rw-r--r--third_party/harfbuzz/contrib/tables/GraphemeBreakProperty.txt1166
-rw-r--r--third_party/harfbuzz/contrib/tables/README17
-rw-r--r--third_party/harfbuzz/contrib/tables/Scripts.txt1747
-rw-r--r--third_party/harfbuzz/contrib/tables/category-parse.py70
-rw-r--r--third_party/harfbuzz/contrib/tables/category-properties.h2869
-rw-r--r--third_party/harfbuzz/contrib/tables/combining-class-parse.py34
-rw-r--r--third_party/harfbuzz/contrib/tables/combining-properties.h247
-rw-r--r--third_party/harfbuzz/contrib/tables/grapheme-break-parse.py45
-rw-r--r--third_party/harfbuzz/contrib/tables/grapheme-break-properties.h1113
-rw-r--r--third_party/harfbuzz/contrib/tables/script-properties.h297
-rw-r--r--third_party/harfbuzz/contrib/tables/scripts-parse.py75
-rw-r--r--third_party/harfbuzz/contrib/tables/unicode_parse_common.py70
-rw-r--r--third_party/harfbuzz/harfbuzz.gyp69
-rw-r--r--third_party/harfbuzz/src/.gitignore7
-rw-r--r--third_party/harfbuzz/src/Makefile.am68
-rw-r--r--third_party/harfbuzz/src/harfbuzz-arabic.c1090
-rw-r--r--third_party/harfbuzz/src/harfbuzz-buffer-private.h107
-rw-r--r--third_party/harfbuzz/src/harfbuzz-buffer.c383
-rw-r--r--third_party/harfbuzz/src/harfbuzz-buffer.h94
-rw-r--r--third_party/harfbuzz/src/harfbuzz-dump-main.c97
-rw-r--r--third_party/harfbuzz/src/harfbuzz-dump.c765
-rw-r--r--third_party/harfbuzz/src/harfbuzz-dump.h41
-rw-r--r--third_party/harfbuzz/src/harfbuzz-external.h157
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gdef-private.h124
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gdef.c1159
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gdef.h135
-rw-r--r--third_party/harfbuzz/src/harfbuzz-global.h118
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gpos-private.h712
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gpos.c6053
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gpos.h149
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gsub-private.h476
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gsub.c4329
-rw-r--r--third_party/harfbuzz/src/harfbuzz-gsub.h141
-rw-r--r--third_party/harfbuzz/src/harfbuzz-hangul.c268
-rw-r--r--third_party/harfbuzz/src/harfbuzz-hebrew.c188
-rw-r--r--third_party/harfbuzz/src/harfbuzz-impl.c84
-rw-r--r--third_party/harfbuzz/src/harfbuzz-impl.h131
-rw-r--r--third_party/harfbuzz/src/harfbuzz-indic.cpp1852
-rw-r--r--third_party/harfbuzz/src/harfbuzz-khmer.c667
-rw-r--r--third_party/harfbuzz/src/harfbuzz-myanmar.c542
-rw-r--r--third_party/harfbuzz/src/harfbuzz-open-private.h102
-rw-r--r--third_party/harfbuzz/src/harfbuzz-open.c1414
-rw-r--r--third_party/harfbuzz/src/harfbuzz-open.h282
-rw-r--r--third_party/harfbuzz/src/harfbuzz-shape.h199
-rw-r--r--third_party/harfbuzz/src/harfbuzz-shaper-all.cpp36
-rw-r--r--third_party/harfbuzz/src/harfbuzz-shaper-private.h167
-rw-r--r--third_party/harfbuzz/src/harfbuzz-shaper.cpp1312
-rw-r--r--third_party/harfbuzz/src/harfbuzz-shaper.h273
-rw-r--r--third_party/harfbuzz/src/harfbuzz-stream-private.h81
-rw-r--r--third_party/harfbuzz/src/harfbuzz-stream.c114
-rw-r--r--third_party/harfbuzz/src/harfbuzz-stream.h45
-rw-r--r--third_party/harfbuzz/src/harfbuzz-thai.c87
-rw-r--r--third_party/harfbuzz/src/harfbuzz-tibetan.c274
-rw-r--r--third_party/harfbuzz/src/harfbuzz.c32
-rw-r--r--third_party/harfbuzz/src/harfbuzz.h38
-rw-r--r--third_party/harfbuzz/tests/Makefile.am7
-rw-r--r--third_party/harfbuzz/tests/linebreaking/.gitignore4
-rw-r--r--third_party/harfbuzz/tests/linebreaking/Makefile.am12
-rw-r--r--third_party/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp108
-rw-r--r--third_party/harfbuzz/tests/linebreaking/main.cpp230
-rw-r--r--third_party/harfbuzz/tests/shaping/.gitignore2
-rw-r--r--third_party/harfbuzz/tests/shaping/Makefile.am14
-rw-r--r--third_party/harfbuzz/tests/shaping/README9
-rw-r--r--third_party/harfbuzz/tests/shaping/main.cpp1035
84 files changed, 39645 insertions, 0 deletions
diff --git a/third_party/harfbuzz/.gitignore b/third_party/harfbuzz/.gitignore
new file mode 100644
index 0000000..572243f
--- /dev/null
+++ b/third_party/harfbuzz/.gitignore
@@ -0,0 +1,20 @@
+INSTALL
+Makefile.in
+aclocal.m4
+autom4te.cache
+config.guess
+config.h.in
+config.sub
+config.h
+configure
+depcomp
+install-sh
+ltmain.sh
+missing
+Makefile
+config.status
+config.log
+libtool
+stamp-h1
+compile
+build
diff --git a/third_party/harfbuzz/AUTHORS b/third_party/harfbuzz/AUTHORS
new file mode 100644
index 0000000..023488a5
--- /dev/null
+++ b/third_party/harfbuzz/AUTHORS
@@ -0,0 +1,6 @@
+David Turner
+Werner Lemberg
+Owen Taylor
+Behdad Esfahbod
+Lars Knoll
+Simon Hausmann
diff --git a/third_party/harfbuzz/COPYING b/third_party/harfbuzz/COPYING
new file mode 100644
index 0000000..820a9e6
--- /dev/null
+++ b/third_party/harfbuzz/COPYING
@@ -0,0 +1,24 @@
+HarfBuzz was previously licensed under different licenses. This was
+changed in January 2008. If you need to relicense your old copies,
+consult the announcement of the license change on the internet.
+Other than that, each copy of HarfBuzz is licensed under the COPYING
+file included with it. The actual license follows:
+
+
+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.
diff --git a/third_party/harfbuzz/ChangeLog b/third_party/harfbuzz/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/harfbuzz/ChangeLog
diff --git a/third_party/harfbuzz/Makefile.am b/third_party/harfbuzz/Makefile.am
new file mode 100644
index 0000000..776b947
--- /dev/null
+++ b/third_party/harfbuzz/Makefile.am
@@ -0,0 +1,2 @@
+
+SUBDIRS = src tests
diff --git a/third_party/harfbuzz/NEWS b/third_party/harfbuzz/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/harfbuzz/NEWS
diff --git a/third_party/harfbuzz/README b/third_party/harfbuzz/README
new file mode 100644
index 0000000..ca2546a
--- /dev/null
+++ b/third_party/harfbuzz/README
@@ -0,0 +1,7 @@
+This is HarfBuzz, an OpenType Layout engine library.
+
+To report bugs or post to discussion mailing list, see:
+
+ http://freedesktop.org/wiki/Software/HarfBuzz
+
+For license information, see the file COPYING.
diff --git a/third_party/harfbuzz/README.google b/third_party/harfbuzz/README.google
new file mode 100644
index 0000000..34fbfeb
--- /dev/null
+++ b/third_party/harfbuzz/README.google
@@ -0,0 +1,32 @@
+Harfbuzz
+
+http://freedesktop.org/wiki/Software/HarfBuzz
+
+This code was taken from cb83c38045a7dd098f8edd4530d328e999a7bbaf
+(git://anongit.freedesktop.org/harfbuzz)
+
+The contrib/ directory was written by us and is in the process of getting upstreamed. Additionally, this patch was applied:
+
+diff --git a/src/harfbuzz-shaper.h b/src/harfbuzz-shaper.h
+index e8f5513..1577b59 100644
+--- a/src/harfbuzz-shaper.h
++++ b/src/harfbuzz-shaper.h
+@@ -242,7 +242,9 @@ typedef struct HB_Font_ {
+ void *userData;
+ } HB_FontRec;
+
+-typedef struct {
++typedef struct HB_ShaperItem_ HB_ShaperItem;
++
++struct HB_ShaperItem_ {
+ const HB_UChar16 *string;
+ hb_uint32 stringLength;
+ HB_ScriptItem item;
+@@ -262,7 +264,7 @@ typedef struct {
+
+ /* internal */
+ HB_Bool kerning_applied; /* out: kerning applied by shaper */
+-} HB_ShaperItem;
++};
+
+ HB_Bool HB_ShapeItem(HB_ShaperItem *item);
diff --git a/third_party/harfbuzz/autogen.sh b/third_party/harfbuzz/autogen.sh
new file mode 100755
index 0000000..7fa1c3d
--- /dev/null
+++ b/third_party/harfbuzz/autogen.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+set -e
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+PROJECT=harfbuzz
+TEST_TYPE=-f
+FILE=src/harfbuzz.h
+ACLOCAL=${ACLOCAL-aclocal}
+LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
+AUTOMAKE=${AUTOMAKE-automake}
+AUTOHEADER=${AUTOHEADER-autoheader}
+AUTOCONF=${AUTOCONF-autoconf}
+LIBTOOLIZE_FLAGS="--copy --force"
+
+DIE=0
+
+have_libtool=false
+if $LIBTOOLIZE --version < /dev/null > /dev/null 2>&1 ; then
+ libtool_version=`$LIBTOOLIZE --version | sed 's/^[^0-9]*\([0-9].[0-9.]*\).*/\1/'`
+ case $libtool_version in
+ 1.4*|1.5*|1.6*|1.7*|2*)
+ have_libtool=true
+ ;;
+ esac
+fi
+if $have_libtool ; then : ; else
+ echo
+ echo "You must have libtool 1.4 installed to compile $PROJECT."
+ echo "Install the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+fi
+
+($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || {
+ echo
+ echo "You must have autoconf installed to compile $PROJECT."
+ echo "libtool the appropriate package for your distribution,"
+ echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/"
+ DIE=1
+}
+
+have_automake=false
+need_libtoolize=true
+if $AUTOMAKE --version < /dev/null > /dev/null 2>&1 ; then
+ automake_version=`$AUTOMAKE --version | grep 'automake (GNU automake)' | sed 's/^[^0-9]*\(.*\)/\1/'`
+ case $automake_version in
+ 1.2*|1.3*|1.4)
+ ;;
+ 1.4*)
+ have_automake=true
+ need_libtoolize=false
+ ;;
+ *)
+ have_automake=true
+ ;;
+ esac
+fi
+if $have_automake ; then : ; else
+ echo
+ echo "You must have automake 1.4-p1 installed to compile $PROJECT."
+ echo "Get ftp://ftp.gnu.org/pub/gnu/automake/automake-1.4-p1.tar.gz"
+ echo "(or a newer version if it is available)"
+ DIE=1
+fi
+
+if test "$DIE" -eq 1; then
+ exit 1
+fi
+
+test $TEST_TYPE $FILE || {
+ echo "You must run this script in the top-level $PROJECT directory"
+ exit 1
+}
+
+if test -z "$AUTOGEN_SUBDIR_MODE"; then
+ if test -z "$*"; then
+ echo "I am going to run ./configure with no arguments - if you wish "
+ echo "to pass any to it, please specify them on the $0 command line."
+ fi
+fi
+
+echo Running $ACLOCAL $ACLOCAL_FLAGS
+$ACLOCAL $ACLOCAL_FLAGS
+
+# optionally run autoheader
+if $AUTOHEADER --version < /dev/null > /dev/null 2>&1; then
+ echo Running $AUTOHEADER
+ $AUTOHEADER
+fi
+
+case $need_libtoolize in
+ true)
+ echo Running $LIBTOOLIZE $LIBTOOLIZE_FLAGS
+ $LIBTOOLIZE $LIBTOOLIZE_FLAGS
+ ;;
+esac
+
+echo Running $AUTOMAKE -a $am_opt
+$AUTOMAKE -a $am_opt
+echo Running $AUTOCONF
+$AUTOCONF
+cd $ORIGDIR
+
+if test -z "$AUTOGEN_SUBDIR_MODE"; then
+ echo Running $srcdir/configure "$@"
+ $srcdir/configure "$@"
+
+ echo
+ echo "Now type 'make' to compile $PROJECT."
+fi
diff --git a/third_party/harfbuzz/config.h b/third_party/harfbuzz/config.h
new file mode 100644
index 0000000..2e856ee
--- /dev/null
+++ b/third_party/harfbuzz/config.h
@@ -0,0 +1,60 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "harfbuzz"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.1"
diff --git a/third_party/harfbuzz/configure.ac b/third_party/harfbuzz/configure.ac
new file mode 100644
index 0000000..8519279
--- /dev/null
+++ b/third_party/harfbuzz/configure.ac
@@ -0,0 +1,54 @@
+AC_INIT(README)
+AM_INIT_AUTOMAKE(harfbuzz, 0.1)
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG
+AM_CONFIG_HEADER(config.h)
+
+if test "x$ac_compiler_gnu" = xyes; then
+ CFLAGS="$CFLAGS -Wall -W -pedantic -ansi"
+ CXXFLAGS="$CXXFLAGS -Wall -W"
+fi
+
+AC_PATH_PROG(ft_config,freetype-config,no)
+if test "$ft_config" = "no"; then
+ AC_MSG_ERROR([You must have freetype installed; see http://www.freetype.org/])
+fi
+
+FREETYPE_CFLAGS="`$ft_config --cflags`"
+FREETYPE_LIBS="`$ft_config --libs`"
+
+AC_SUBST(FREETYPE_LIBS)
+AC_SUBST(FREETYPE_CFLAGS)
+
+AC_ARG_ENABLE(qt, AS_HELP_STRING([--disable-qt], [Build Qt support (default: auto)]), [QT=$enableval], [QT=auto])
+
+if test "x$QT" = xauto; then
+ PKG_CHECK_MODULES(QT, [QtGui >= 4.3], [QT=yes], [QT=no])
+fi
+if test "x$QT" = xyes; then
+ PKG_CHECK_MODULES(QT_GUI, [QtGui >= 4.3])
+ PKG_CHECK_MODULES(QT_QTEST, [QtTest >= 4.3])
+
+ _PKG_CONFIG(QT_INCDIR, [variable=includedir], [QtGui >= 4.3])
+ QT_GUI_CFLAGS="$QT_GUI_CFLAGS -I$pkg_cv_QT_INCDIR/../Qt"
+
+ AC_SUBST(QT_GUI_CFLAGS)
+ AC_SUBST(QT_GUI_LIBS)
+ AC_SUBST(QT_QTEST_CFLAGS)
+ AC_SUBST(QT_QTEST_LIBS)
+
+ _PKG_CONFIG(QT_MOC, [variable=moc_location], [QtGui >= 4.3])
+ QT_MOC=$pkg_cv_QT_MOC
+ AC_SUBST(QT_MOC)
+fi
+AM_CONDITIONAL(QT, [test "x$QT" = xyes])
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+tests/Makefile
+tests/linebreaking/Makefile
+tests/shaping/Makefile
+])
diff --git a/third_party/harfbuzz/contrib/README b/third_party/harfbuzz/contrib/README
new file mode 100644
index 0000000..074cc52
--- /dev/null
+++ b/third_party/harfbuzz/contrib/README
@@ -0,0 +1,9 @@
+Harfbuzz requires several functions to be defined in order to work with the
+platform's Unicode tables etc.
+
+If you are building on top of Qt4 you should look at the code in the tests/
+directory for examples of how to hook up Qt4 functions to Harfbuzz.
+
+Otherwise, this directory contains examples of using downloaded Unicode tables
+and/or glib to host Harfbuzz. You should read the README file in tables/ for how
+to build the header files for some of the Unicode tables.
diff --git a/third_party/harfbuzz/contrib/harfbuzz-freetype.c b/third_party/harfbuzz/contrib/harfbuzz-freetype.c
new file mode 100644
index 0000000..a2962df
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-freetype.c
@@ -0,0 +1,149 @@
+#include <stdint.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+
+#if 0
+#include <freetype/freetype.h>
+#include <freetype/tttables.h>
+#endif
+
+#include <harfbuzz-shaper.h>
+#include "harfbuzz-unicode.h"
+
+static HB_Bool
+hb_freetype_string_to_glyphs(HB_Font font,
+ const HB_UChar16 *chars, hb_uint32 len,
+ HB_Glyph *glyphs, hb_uint32 *numGlyphs,
+ HB_Bool is_rtl) {
+ FT_Face face = (FT_Face) font->userData;
+ if (len > *numGlyphs)
+ return 0;
+
+ size_t i = 0, j = 0;
+ while (i < len) {
+ const uint32_t cp = utf16_to_code_point(chars, len, &i);
+ glyphs[j++] = FT_Get_Char_Index(face, cp);
+ }
+
+ *numGlyphs = j;
+
+ return 1;
+}
+
+static void
+hb_freetype_advances_get(HB_Font font, const HB_Glyph *glyphs, hb_uint32 len,
+ HB_Fixed *advances, int flags) {
+ FT_Face face = (FT_Face) font->userData;
+
+ hb_uint32 i;
+ for (i = 0; i < len; ++i) {
+ const FT_Error error = FT_Load_Glyph(face, glyphs[i], FT_LOAD_DEFAULT);
+ if (error) {
+ advances[i] = 0;
+ continue;
+ }
+
+ advances[i] = face->glyph->advance.x;
+ }
+}
+
+static HB_Bool
+hb_freetype_can_render(HB_Font font, const HB_UChar16 *chars, hb_uint32 len) {
+ FT_Face face = (FT_Face)font->userData;
+
+ size_t i = 0;
+ while (i < len) {
+ const uint32_t cp = utf16_to_code_point(chars, len, &i);
+ if (FT_Get_Char_Index(face, cp) == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static HB_Error
+hb_freetype_outline_point_get(HB_Font font, HB_Glyph glyph, int flags,
+ hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos,
+ hb_uint32 *n_points) {
+ HB_Error error = HB_Err_Ok;
+ FT_Face face = (FT_Face) font->userData;
+
+ int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
+
+ if ((error = (HB_Error) FT_Load_Glyph(face, glyph, load_flags)))
+ return error;
+
+ if (face->glyph->format != ft_glyph_format_outline)
+ return (HB_Error)HB_Err_Invalid_SubTable;
+
+ *n_points = face->glyph->outline.n_points;
+ if (!(*n_points))
+ return HB_Err_Ok;
+
+ if (point > *n_points)
+ return (HB_Error)HB_Err_Invalid_SubTable;
+
+ *xpos = face->glyph->outline.points[point].x;
+ *ypos = face->glyph->outline.points[point].y;
+
+ return HB_Err_Ok;
+}
+
+static void
+hb_freetype_glyph_metrics_get(HB_Font font, HB_Glyph glyph,
+ HB_GlyphMetrics *metrics) {
+ FT_Face face = (FT_Face) font->userData;
+
+ const FT_Error error = FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT);
+ if (error) {
+ metrics->x = metrics->y = metrics->width = metrics->height = 0;
+ metrics->xOffset = metrics->yOffset = 0;
+ return;
+ }
+
+ const FT_Glyph_Metrics *ftmetrics = &face->glyph->metrics;
+ metrics->width = ftmetrics->width;
+ metrics->height = ftmetrics->height;
+ metrics->x = ftmetrics->horiAdvance;
+ metrics->y = 0; // unclear what this is
+ metrics->xOffset = ftmetrics->horiBearingX;
+ metrics->yOffset = ftmetrics->horiBearingY;
+}
+
+static HB_Fixed
+hb_freetype_font_metric_get(HB_Font font, HB_FontMetric metric) {
+ FT_Face face = (FT_Face) font->userData;
+
+ switch (metric) {
+ case HB_FontAscent:
+ // Note that we aren't scanning the VDMX table which we probably would in
+ // an ideal world.
+ return face->ascender;
+ default:
+ return 0;
+ }
+}
+
+const HB_FontClass hb_freetype_class = {
+ hb_freetype_string_to_glyphs,
+ hb_freetype_advances_get,
+ hb_freetype_can_render,
+ hb_freetype_outline_point_get,
+ hb_freetype_glyph_metrics_get,
+ hb_freetype_font_metric_get,
+};
+
+HB_Error
+hb_freetype_table_sfnt_get(void *voidface, const HB_Tag tag, HB_Byte *buffer, HB_UInt *len) {
+ FT_Face face = (FT_Face) voidface;
+ FT_ULong ftlen = *len;
+
+ if (!FT_IS_SFNT(face))
+ return HB_Err_Invalid_Argument;
+
+ const FT_Error error = FT_Load_Sfnt_Table(face, tag, 0, buffer, &ftlen);
+ *len = ftlen;
+ return (HB_Error) error;
+}
diff --git a/third_party/harfbuzz/contrib/harfbuzz-freetype.h b/third_party/harfbuzz/contrib/harfbuzz-freetype.h
new file mode 100644
index 0000000..628be16
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-freetype.h
@@ -0,0 +1,9 @@
+#ifndef HB_FREETYPE_H_
+#define HB_FREETYPE_H_
+
+extern const HB_FontClass hb_freetype_class;
+
+HB_Error hb_freetype_table_sfnt_get(void *voidface, const HB_Tag tag,
+ HB_Byte *buffer, HB_UInt *len);
+
+#endif // HB_FREETYPE_H_
diff --git a/third_party/harfbuzz/contrib/harfbuzz-unicode-glib.c b/third_party/harfbuzz/contrib/harfbuzz-unicode-glib.c
new file mode 100644
index 0000000..6a13433
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-unicode-glib.c
@@ -0,0 +1,169 @@
+#include "harfbuzz-external.h"
+
+#include <glib.h>
+
+static int
+hb_category_for_char(HB_UChar32 ch) {
+ switch (g_unichar_type(ch)) {
+ case G_UNICODE_CONTROL:
+ return HB_Other_Control;
+ case G_UNICODE_FORMAT:
+ return HB_Other_Format;
+ case G_UNICODE_UNASSIGNED:
+ return HB_Other_NotAssigned;
+ case G_UNICODE_PRIVATE_USE:
+ return HB_Other_PrivateUse;
+ case G_UNICODE_SURROGATE:
+ return HB_Other_Surrogate;
+ case G_UNICODE_LOWERCASE_LETTER:
+ return HB_Letter_Lowercase;
+ case G_UNICODE_MODIFIER_LETTER:
+ return HB_Letter_Modifier;
+ case G_UNICODE_OTHER_LETTER:
+ return HB_Letter_Other;
+ case G_UNICODE_TITLECASE_LETTER:
+ return HB_Letter_Titlecase;
+ case G_UNICODE_UPPERCASE_LETTER:
+ return HB_Letter_Uppercase;
+ case G_UNICODE_COMBINING_MARK:
+ return HB_Mark_SpacingCombining;
+ case G_UNICODE_ENCLOSING_MARK:
+ return HB_Mark_Enclosing;
+ case G_UNICODE_NON_SPACING_MARK:
+ return HB_Mark_NonSpacing;
+ case G_UNICODE_DECIMAL_NUMBER:
+ return HB_Number_DecimalDigit;
+ case G_UNICODE_LETTER_NUMBER:
+ return HB_Number_Letter;
+ case G_UNICODE_OTHER_NUMBER:
+ return HB_Number_Other;
+ case G_UNICODE_CONNECT_PUNCTUATION:
+ return HB_Punctuation_Connector;
+ case G_UNICODE_DASH_PUNCTUATION:
+ return HB_Punctuation_Dash;
+ case G_UNICODE_CLOSE_PUNCTUATION:
+ return HB_Punctuation_Close;
+ case G_UNICODE_FINAL_PUNCTUATION:
+ return HB_Punctuation_FinalQuote;
+ case G_UNICODE_INITIAL_PUNCTUATION:
+ return HB_Punctuation_InitialQuote;
+ case G_UNICODE_OTHER_PUNCTUATION:
+ return HB_Punctuation_Other;
+ case G_UNICODE_OPEN_PUNCTUATION:
+ return HB_Punctuation_Open;
+ case G_UNICODE_CURRENCY_SYMBOL:
+ return HB_Symbol_Currency;
+ case G_UNICODE_MODIFIER_SYMBOL:
+ return HB_Symbol_Modifier;
+ case G_UNICODE_MATH_SYMBOL:
+ return HB_Symbol_Math;
+ case G_UNICODE_OTHER_SYMBOL:
+ return HB_Symbol_Other;
+ case G_UNICODE_LINE_SEPARATOR:
+ return HB_Separator_Line;
+ case G_UNICODE_PARAGRAPH_SEPARATOR:
+ return HB_Separator_Paragraph;
+ case G_UNICODE_SPACE_SEPARATOR:
+ return HB_Separator_Space;
+ default:
+ return HB_Symbol_Other;
+ }
+}
+
+HB_LineBreakClass
+HB_GetLineBreakClass(HB_UChar32 ch) {
+ switch (g_unichar_break_type(ch)) {
+ case G_UNICODE_BREAK_MANDATORY:
+ return HB_LineBreak_BK;
+ case G_UNICODE_BREAK_CARRIAGE_RETURN:
+ return HB_LineBreak_CR;
+ case G_UNICODE_BREAK_LINE_FEED:
+ return HB_LineBreak_LF;
+ case G_UNICODE_BREAK_COMBINING_MARK:
+ return HB_LineBreak_CM;
+ case G_UNICODE_BREAK_SURROGATE:
+ return HB_LineBreak_SG;
+ case G_UNICODE_BREAK_ZERO_WIDTH_SPACE:
+ return HB_LineBreak_ZW;
+ case G_UNICODE_BREAK_INSEPARABLE:
+ return HB_LineBreak_IN;
+ case G_UNICODE_BREAK_NON_BREAKING_GLUE:
+ return HB_LineBreak_GL;
+ case G_UNICODE_BREAK_CONTINGENT:
+ return HB_LineBreak_AL;
+ case G_UNICODE_BREAK_SPACE:
+ return HB_LineBreak_SP;
+ case G_UNICODE_BREAK_AFTER:
+ return HB_LineBreak_BA;
+ case G_UNICODE_BREAK_BEFORE:
+ return HB_LineBreak_BB;
+ case G_UNICODE_BREAK_BEFORE_AND_AFTER:
+ return HB_LineBreak_B2;
+ case G_UNICODE_BREAK_HYPHEN:
+ return HB_LineBreak_HY;
+ case G_UNICODE_BREAK_NON_STARTER:
+ return HB_LineBreak_NS;
+ case G_UNICODE_BREAK_OPEN_PUNCTUATION:
+ return HB_LineBreak_OP;
+ case G_UNICODE_BREAK_CLOSE_PUNCTUATION:
+ return HB_LineBreak_CL;
+ case G_UNICODE_BREAK_QUOTATION:
+ return HB_LineBreak_QU;
+ case G_UNICODE_BREAK_EXCLAMATION:
+ return HB_LineBreak_EX;
+ case G_UNICODE_BREAK_IDEOGRAPHIC:
+ return HB_LineBreak_ID;
+ case G_UNICODE_BREAK_NUMERIC:
+ return HB_LineBreak_NU;
+ case G_UNICODE_BREAK_INFIX_SEPARATOR:
+ return HB_LineBreak_IS;
+ case G_UNICODE_BREAK_SYMBOL:
+ return HB_LineBreak_SY;
+ case G_UNICODE_BREAK_ALPHABETIC:
+ return HB_LineBreak_AL;
+ case G_UNICODE_BREAK_PREFIX:
+ return HB_LineBreak_PR;
+ case G_UNICODE_BREAK_POSTFIX:
+ return HB_LineBreak_PO;
+ case G_UNICODE_BREAK_COMPLEX_CONTEXT:
+ return HB_LineBreak_SA;
+ case G_UNICODE_BREAK_AMBIGUOUS:
+ return HB_LineBreak_AL;
+ case G_UNICODE_BREAK_UNKNOWN:
+ return HB_LineBreak_AL;
+ case G_UNICODE_BREAK_NEXT_LINE:
+ return HB_LineBreak_AL;
+ case G_UNICODE_BREAK_WORD_JOINER:
+ return HB_LineBreak_WJ;
+ case G_UNICODE_BREAK_HANGUL_L_JAMO:
+ return HB_LineBreak_JL;
+ case G_UNICODE_BREAK_HANGUL_V_JAMO:
+ return HB_LineBreak_JV;
+ case G_UNICODE_BREAK_HANGUL_T_JAMO:
+ return HB_LineBreak_JT;
+ case G_UNICODE_BREAK_HANGUL_LV_SYLLABLE:
+ return HB_LineBreak_H2;
+ case G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE:
+ return HB_LineBreak_H3;
+ default:
+ return HB_LineBreak_AL;
+ }
+}
+
+int
+HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) {
+ return g_unichar_combining_class(ch);
+}
+
+void
+HB_GetUnicodeCharProperties(HB_UChar32 ch,
+ HB_CharCategory *category,
+ int *combiningClass) {
+ *category = hb_category_for_char(ch);
+ *combiningClass = g_unichar_combining_class(ch);
+}
+
+HB_CharCategory
+HB_GetUnicodeCharCategory(HB_UChar32 ch) {
+ return hb_category_for_char(ch);
+}
diff --git a/third_party/harfbuzz/contrib/harfbuzz-unicode-tables.c b/third_party/harfbuzz/contrib/harfbuzz-unicode-tables.c
new file mode 100644
index 0000000..3c3fead6
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-unicode-tables.c
@@ -0,0 +1,84 @@
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <harfbuzz-external.h>
+
+#include "tables/category-properties.h"
+#include "tables/combining-properties.h"
+
+HB_LineBreakClass
+HB_GetLineBreakClass(HB_UChar32 ch) {
+ abort();
+ return 0;
+}
+
+static int
+combining_property_cmp(const void *vkey, const void *vcandidate) {
+ const uint32_t key = (uint32_t) (intptr_t) vkey;
+ const struct combining_property *candidate = vcandidate;
+
+ if (key < candidate->range_start) {
+ return -1;
+ } else if (key > candidate->range_end) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int
+code_point_to_combining_class(HB_UChar32 cp) {
+ const void *vprop = bsearch((void *) (intptr_t) cp, combining_properties,
+ combining_properties_count,
+ sizeof(struct combining_property),
+ combining_property_cmp);
+ if (!vprop)
+ return 0;
+
+ return ((const struct combining_property *) vprop)->klass;
+}
+
+int
+HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) {
+ return code_point_to_combining_class(ch);
+ return 0;
+}
+
+static int
+category_property_cmp(const void *vkey, const void *vcandidate) {
+ const uint32_t key = (uint32_t) (intptr_t) vkey;
+ const struct category_property *candidate = vcandidate;
+
+ if (key < candidate->range_start) {
+ return -1;
+ } else if (key > candidate->range_end) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static HB_CharCategory
+code_point_to_category(HB_UChar32 cp) {
+ const void *vprop = bsearch((void *) (intptr_t) cp, category_properties,
+ category_properties_count,
+ sizeof(struct category_property),
+ category_property_cmp);
+ if (!vprop)
+ return HB_NoCategory;
+
+ return ((const struct category_property *) vprop)->category;
+}
+
+void
+HB_GetUnicodeCharProperties(HB_UChar32 ch,
+ HB_CharCategory *category,
+ int *combiningClass) {
+ *category = code_point_to_category(ch);
+ *combiningClass = code_point_to_combining_class(ch);
+}
+
+HB_CharCategory
+HB_GetUnicodeCharCategory(HB_UChar32 ch) {
+ return code_point_to_category(ch);
+}
diff --git a/third_party/harfbuzz/contrib/harfbuzz-unicode.c b/third_party/harfbuzz/contrib/harfbuzz-unicode.c
new file mode 100644
index 0000000..9b3c43e
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-unicode.c
@@ -0,0 +1,264 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <harfbuzz-external.h>
+#include <harfbuzz-impl.h>
+#include <harfbuzz-shaper.h>
+#include "harfbuzz-unicode.h"
+
+#include "tables/script-properties.h"
+#include "tables/grapheme-break-properties.h"
+
+uint32_t
+utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter) {
+ const uint16_t v = chars[(*iter)++];
+ if (HB_IsHighSurrogate(v)) {
+ // surrogate pair
+ if (*iter >= len) {
+ // the surrogate is incomplete.
+ return HB_InvalidCodePoint;
+ }
+ const uint16_t v2 = chars[(*iter)++];
+ if (!HB_IsLowSurrogate(v2)) {
+ // invalidate surrogate pair.
+ return HB_InvalidCodePoint;
+ }
+
+ return HB_SurrogateToUcs4(v, v2);
+ }
+
+ if (HB_IsLowSurrogate(v)) {
+ // this isn't a valid code point
+ return HB_InvalidCodePoint;
+ }
+
+ return v;
+}
+
+uint32_t
+utf16_to_code_point_prev(const uint16_t *chars, size_t len, ssize_t *iter) {
+ const uint16_t v = chars[(*iter)--];
+ if (HB_IsLowSurrogate(v)) {
+ // surrogate pair
+ if (*iter < 0) {
+ // the surrogate is incomplete.
+ return HB_InvalidCodePoint;
+ }
+ const uint16_t v2 = chars[(*iter)--];
+ if (!HB_IsHighSurrogate(v2)) {
+ // invalidate surrogate pair.
+ return HB_InvalidCodePoint;
+ }
+
+ return HB_SurrogateToUcs4(v2, v);
+ }
+
+ if (HB_IsHighSurrogate(v)) {
+ // this isn't a valid code point
+ return HB_InvalidCodePoint;
+ }
+
+ return v;
+}
+
+static int
+script_property_cmp(const void *vkey, const void *vcandidate) {
+ const uint32_t key = (uint32_t) (intptr_t) vkey;
+ const struct script_property *candidate = vcandidate;
+
+ if (key < candidate->range_start) {
+ return -1;
+ } else if (key > candidate->range_end) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+HB_Script
+code_point_to_script(uint32_t cp) {
+ const void *vprop = bsearch((void *) (intptr_t) cp, script_properties,
+ script_properties_count,
+ sizeof(struct script_property),
+ script_property_cmp);
+ if (!vprop)
+ return HB_Script_Common;
+
+ return ((const struct script_property *) vprop)->script;
+}
+
+char
+hb_utf16_script_run_next(unsigned *num_code_points, HB_ScriptItem *output,
+ const uint16_t *chars, size_t len, ssize_t *iter) {
+ if (*iter == len)
+ return 0;
+
+ output->pos = *iter;
+ const uint32_t init_cp = utf16_to_code_point(chars, len, iter);
+ unsigned cps = 1;
+ if (init_cp == HB_InvalidCodePoint)
+ return 0;
+ const HB_Script init_script = code_point_to_script(init_cp);
+ HB_Script current_script = init_script;
+ output->script = init_script;
+
+ for (;;) {
+ if (*iter == len)
+ break;
+ const ssize_t prev_iter = *iter;
+ const uint32_t cp = utf16_to_code_point(chars, len, iter);
+ if (cp == HB_InvalidCodePoint)
+ return 0;
+ cps++;
+ const HB_Script script = code_point_to_script(cp);
+
+ if (script != current_script) {
+ if (current_script == init_script == HB_Script_Inherited) {
+ // If we started off as inherited, we take whatever we can find.
+ output->script = script;
+ current_script = script;
+ continue;
+ } else if (script == HB_Script_Inherited) {
+ current_script = script;
+ continue;
+ } else {
+ *iter = prev_iter;
+ cps--;
+ break;
+ }
+ }
+ }
+
+ if (output->script == HB_Script_Inherited)
+ output->script = HB_Script_Common;
+
+ output->length = *iter - output->pos;
+ if (num_code_points)
+ *num_code_points = cps;
+ return 1;
+}
+
+char
+hb_utf16_script_run_prev(unsigned *num_code_points, HB_ScriptItem *output,
+ const uint16_t *chars, size_t len, ssize_t *iter) {
+ if (*iter == (size_t) -1)
+ return 0;
+
+ const size_t ending_index = *iter;
+ const uint32_t init_cp = utf16_to_code_point_prev(chars, len, iter);
+ unsigned cps = 1;
+ if (init_cp == HB_InvalidCodePoint)
+ return 0;
+ const HB_Script init_script = code_point_to_script(init_cp);
+ HB_Script current_script = init_script;
+ output->script = init_script;
+
+ for (;;) {
+ if (*iter < 0)
+ break;
+ const ssize_t prev_iter = *iter;
+ const uint32_t cp = utf16_to_code_point_prev(chars, len, iter);
+ if (cp == HB_InvalidCodePoint)
+ return 0;
+ cps++;
+ const HB_Script script = code_point_to_script(cp);
+
+ if (script != current_script) {
+ if (current_script == init_script == HB_Script_Inherited) {
+ // If we started off as inherited, we take whatever we can find.
+ output->script = script;
+ current_script = script;
+ continue;
+ } else if (script == HB_Script_Inherited) {
+ current_script = script;
+ continue;
+ } else {
+ *iter = prev_iter;
+ cps--;
+ break;
+ }
+ }
+ }
+
+ if (output->script == HB_Script_Inherited)
+ output->script = HB_Script_Common;
+
+ output->pos = *iter + 1;
+ output->length = ending_index - *iter;
+ if (num_code_points)
+ *num_code_points = cps;
+ return 1;
+}
+
+static int
+grapheme_break_property_cmp(const void *vkey, const void *vcandidate) {
+ const uint32_t key = (uint32_t) (intptr_t) vkey;
+ const struct grapheme_break_property *candidate = vcandidate;
+
+ if (key < candidate->range_start) {
+ return -1;
+ } else if (key > candidate->range_end) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+HB_GraphemeClass
+HB_GetGraphemeClass(HB_UChar32 ch) {
+ const void *vprop = bsearch((void *) (intptr_t) ch, grapheme_break_properties,
+ grapheme_break_properties_count,
+ sizeof(struct grapheme_break_property),
+ grapheme_break_property_cmp);
+ if (!vprop)
+ return HB_Grapheme_Other;
+
+ return ((const struct grapheme_break_property *) vprop)->klass;
+}
+
+HB_WordClass
+HB_GetWordClass(HB_UChar32 ch) {
+ abort();
+ return 0;
+}
+
+HB_SentenceClass
+HB_GetSentenceClass(HB_UChar32 ch) {
+ abort();
+ return 0;
+}
+
+void
+HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *gclass, HB_LineBreakClass *breakclass) {
+ *gclass = HB_GetGraphemeClass(ch);
+ *breakclass = HB_GetLineBreakClass(ch);
+}
+
+HB_UChar16
+HB_GetMirroredChar(HB_UChar16 ch) {
+ abort();
+ return 0;
+}
+
+void *
+HB_Library_Resolve(const char *library, const char *symbol) {
+ abort();
+ return NULL;
+}
+
+void *
+HB_TextCodecForMib(int mib) {
+ abort();
+ return NULL;
+}
+
+char *
+HB_TextCodec_ConvertFromUnicode(void *codec, const HB_UChar16 *unicode, hb_uint32 length, hb_uint32 *outputLength) {
+ abort();
+ return NULL;
+}
+
+void
+HB_TextCodec_FreeResult(char *v) {
+ abort();
+}
diff --git a/third_party/harfbuzz/contrib/harfbuzz-unicode.h b/third_party/harfbuzz/contrib/harfbuzz-unicode.h
new file mode 100644
index 0000000..f28b3c3
--- /dev/null
+++ b/third_party/harfbuzz/contrib/harfbuzz-unicode.h
@@ -0,0 +1,54 @@
+#ifndef SCRIPT_IDENTIFY_H_
+#define SCRIPT_IDENTIFY_H_
+
+#include <stdint.h>
+
+#include <harfbuzz-shaper.h>
+
+static const uint32_t HB_InvalidCodePoint = 0xffffffffu;
+
+// -----------------------------------------------------------------------------
+// Return the next Unicode code point from a UTF-16 vector
+// chars: a pointer to @len words
+// iter: (input/output) an index into @chars. This is updated.
+// returns: HB_InvalidCodePoint on error and the code point otherwise.
+// -----------------------------------------------------------------------------
+uint32_t utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter);
+
+// -----------------------------------------------------------------------------
+// Like the above, except that the code points are traversed backwards. Thus,
+// on the first call, |iter| should be |len| - 1.
+// -----------------------------------------------------------------------------
+uint32_t utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter);
+
+// -----------------------------------------------------------------------------
+// Return the script of the given code point
+// -----------------------------------------------------------------------------
+HB_Script code_point_to_script(uint32_t cp);
+
+// -----------------------------------------------------------------------------
+// Find the next script run in a UTF-16 string.
+//
+// A script run is a subvector of codepoints, all of which are in the same
+// script. A run will never cut a surrogate pair in half at either end.
+//
+// num_code_points: (output, maybe NULL) the number of code points in the run
+// output: (output) the @pos, @length and @script fields are set on success
+// chars: the UTF-16 string
+// len: the length of @chars, in words
+// iter: (in/out) the current index into the string. This should be 0 for the
+// first call and is updated on exit.
+//
+// returns: non-zero if a script run was found and returned.
+// -----------------------------------------------------------------------------
+char hb_utf16_script_run_next(unsigned *num_code_points, HB_ScriptItem *output,
+ const uint16_t *chars, size_t len, ssize_t *iter);
+
+// -----------------------------------------------------------------------------
+// This is the same as above, except that the input is traversed backwards.
+// Thus, on the first call, |iter| should be |len| - 1.
+// -----------------------------------------------------------------------------
+char hb_utf16_script_run_prev(unsigned *num_code_points, HB_ScriptItem *output,
+ const uint16_t *chars, size_t len, ssize_t *iter);
+
+#endif
diff --git a/third_party/harfbuzz/contrib/tables/DerivedCombiningClass.txt b/third_party/harfbuzz/contrib/tables/DerivedCombiningClass.txt
new file mode 100644
index 0000000..f30fb0b
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/DerivedCombiningClass.txt
@@ -0,0 +1,1881 @@
+# DerivedCombiningClass-5.1.0.txt
+# Date: 2008-03-20, 17:54:45 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2008 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+
+# ================================================
+
+# Combining Class (listing UnicodeData.txt, field 3: see UCD.html)
+
+# All code points not explicitly listed for Canonical_Combining_Class
+# have the value Not_Reordered (0).
+
+# @missing: 0000..10FFFF; Not_Reordered
+
+# ================================================
+
+# Canonical_Combining_Class=Not_Reordered
+
+0000..001F ; 0 # Cc [32] <control-0000>..<control-001F>
+0020 ; 0 # Zs SPACE
+0021..0023 ; 0 # Po [3] EXCLAMATION MARK..NUMBER SIGN
+0024 ; 0 # Sc DOLLAR SIGN
+0025..0027 ; 0 # Po [3] PERCENT SIGN..APOSTROPHE
+0028 ; 0 # Ps LEFT PARENTHESIS
+0029 ; 0 # Pe RIGHT PARENTHESIS
+002A ; 0 # Po ASTERISK
+002B ; 0 # Sm PLUS SIGN
+002C ; 0 # Po COMMA
+002D ; 0 # Pd HYPHEN-MINUS
+002E..002F ; 0 # Po [2] FULL STOP..SOLIDUS
+0030..0039 ; 0 # Nd [10] DIGIT ZERO..DIGIT NINE
+003A..003B ; 0 # Po [2] COLON..SEMICOLON
+003C..003E ; 0 # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+003F..0040 ; 0 # Po [2] QUESTION MARK..COMMERCIAL AT
+0041..005A ; 0 # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+005B ; 0 # Ps LEFT SQUARE BRACKET
+005C ; 0 # Po REVERSE SOLIDUS
+005D ; 0 # Pe RIGHT SQUARE BRACKET
+005E ; 0 # Sk CIRCUMFLEX ACCENT
+005F ; 0 # Pc LOW LINE
+0060 ; 0 # Sk GRAVE ACCENT
+0061..007A ; 0 # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+007B ; 0 # Ps LEFT CURLY BRACKET
+007C ; 0 # Sm VERTICAL LINE
+007D ; 0 # Pe RIGHT CURLY BRACKET
+007E ; 0 # Sm TILDE
+007F..009F ; 0 # Cc [33] <control-007F>..<control-009F>
+00A0 ; 0 # Zs NO-BREAK SPACE
+00A1 ; 0 # Po INVERTED EXCLAMATION MARK
+00A2..00A5 ; 0 # Sc [4] CENT SIGN..YEN SIGN
+00A6..00A7 ; 0 # So [2] BROKEN BAR..SECTION SIGN
+00A8 ; 0 # Sk DIAERESIS
+00A9 ; 0 # So COPYRIGHT SIGN
+00AA ; 0 # L& FEMININE ORDINAL INDICATOR
+00AB ; 0 # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+00AC ; 0 # Sm NOT SIGN
+00AD ; 0 # Cf SOFT HYPHEN
+00AE ; 0 # So REGISTERED SIGN
+00AF ; 0 # Sk MACRON
+00B0 ; 0 # So DEGREE SIGN
+00B1 ; 0 # Sm PLUS-MINUS SIGN
+00B2..00B3 ; 0 # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+00B4 ; 0 # Sk ACUTE ACCENT
+00B5 ; 0 # L& MICRO SIGN
+00B6 ; 0 # So PILCROW SIGN
+00B7 ; 0 # Po MIDDLE DOT
+00B8 ; 0 # Sk CEDILLA
+00B9 ; 0 # No SUPERSCRIPT ONE
+00BA ; 0 # L& MASCULINE ORDINAL INDICATOR
+00BB ; 0 # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+00BC..00BE ; 0 # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+00BF ; 0 # Po INVERTED QUESTION MARK
+00C0..00D6 ; 0 # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D7 ; 0 # Sm MULTIPLICATION SIGN
+00D8..00F6 ; 0 # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F7 ; 0 # Sm DIVISION SIGN
+00F8..01BA ; 0 # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; 0 # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; 0 # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; 0 # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; 0 # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; 0 # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; 0 # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02C1 ; 0 # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C2..02C5 ; 0 # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02C6..02D1 ; 0 # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02D2..02DF ; 0 # Sk [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT
+02E0..02E4 ; 0 # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02E5..02EB ; 0 # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02EC ; 0 # Lm MODIFIER LETTER VOICING
+02ED ; 0 # Sk MODIFIER LETTER UNASPIRATED
+02EE ; 0 # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+02EF..02FF ; 0 # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+034F ; 0 # Mn COMBINING GRAPHEME JOINER
+0370..0373 ; 0 # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0374 ; 0 # Lm GREEK NUMERAL SIGN
+0375 ; 0 # Sk GREEK LOWER NUMERAL SIGN
+0376..0377 ; 0 # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; 0 # Lm GREEK YPOGEGRAMMENI
+037B..037D ; 0 # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+037E ; 0 # Po GREEK QUESTION MARK
+0384..0385 ; 0 # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+0386 ; 0 # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0387 ; 0 # Po GREEK ANO TELEIA
+0388..038A ; 0 # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; 0 # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; 0 # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03F5 ; 0 # L& [83] GREEK CAPITAL LETTER SIGMA..GREEK LUNATE EPSILON SYMBOL
+03F6 ; 0 # Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+03F7..0481 ; 0 # L& [139] GREEK CAPITAL LETTER SHO..CYRILLIC SMALL LETTER KOPPA
+0482 ; 0 # So CYRILLIC THOUSANDS SIGN
+0488..0489 ; 0 # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+048A..0523 ; 0 # L& [154] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+0531..0556 ; 0 # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; 0 # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+055A..055F ; 0 # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+0561..0587 ; 0 # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+0589 ; 0 # Po ARMENIAN FULL STOP
+058A ; 0 # Pd ARMENIAN HYPHEN
+05BE ; 0 # Pd HEBREW PUNCTUATION MAQAF
+05C0 ; 0 # Po HEBREW PUNCTUATION PASEQ
+05C3 ; 0 # Po HEBREW PUNCTUATION SOF PASUQ
+05C6 ; 0 # Po HEBREW PUNCTUATION NUN HAFUKHA
+05D0..05EA ; 0 # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; 0 # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+05F3..05F4 ; 0 # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+0600..0603 ; 0 # Cf [4] ARABIC NUMBER SIGN..ARABIC SIGN SAFHA
+0606..0608 ; 0 # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+0609..060A ; 0 # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+060B ; 0 # Sc AFGHANI SIGN
+060C..060D ; 0 # Po [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+060E..060F ; 0 # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+061B ; 0 # Po ARABIC SEMICOLON
+061E..061F ; 0 # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
+0621..063F ; 0 # Lo [31] ARABIC LETTER HAMZA..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0640 ; 0 # Lm ARABIC TATWEEL
+0641..064A ; 0 # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+0660..0669 ; 0 # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+066A..066D ; 0 # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+066E..066F ; 0 # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; 0 # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D4 ; 0 # Po ARABIC FULL STOP
+06D5 ; 0 # Lo ARABIC LETTER AE
+06DD ; 0 # Cf ARABIC END OF AYAH
+06DE ; 0 # Me ARABIC START OF RUB EL HIZB
+06E5..06E6 ; 0 # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E9 ; 0 # So ARABIC PLACE OF SAJDAH
+06EE..06EF ; 0 # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06F0..06F9 ; 0 # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+06FA..06FC ; 0 # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FD..06FE ; 0 # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+06FF ; 0 # Lo ARABIC LETTER HEH WITH INVERTED V
+0700..070D ; 0 # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+070F ; 0 # Cf SYRIAC ABBREVIATION MARK
+0710 ; 0 # Lo SYRIAC LETTER ALAPH
+0712..072F ; 0 # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; 0 # Lo [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07A6..07B0 ; 0 # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07B1 ; 0 # Lo THAANA LETTER NAA
+07C0..07C9 ; 0 # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+07CA..07EA ; 0 # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07F4..07F5 ; 0 # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07F6 ; 0 # So NKO SYMBOL OO DENNEN
+07F7..07F9 ; 0 # Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+07FA ; 0 # Lm NKO LAJANYALAN
+0901..0902 ; 0 # Mn [2] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+0903 ; 0 # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; 0 # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093D ; 0 # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; 0 # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; 0 # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; 0 # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+0950 ; 0 # Lo DEVANAGARI OM
+0958..0961 ; 0 # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0962..0963 ; 0 # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0964..0965 ; 0 # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+0966..096F ; 0 # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+0970 ; 0 # Po DEVANAGARI ABBREVIATION SIGN
+0971 ; 0 # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972 ; 0 # Lo DEVANAGARI LETTER CANDRA A
+097B..097F ; 0 # Lo [5] DEVANAGARI LETTER GGA..DEVANAGARI LETTER BBA
+0981 ; 0 # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; 0 # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; 0 # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; 0 # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; 0 # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; 0 # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; 0 # Lo BENGALI LETTER LA
+09B6..09B9 ; 0 # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; 0 # Lo BENGALI SIGN AVAGRAHA
+09BE..09C0 ; 0 # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; 0 # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; 0 # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; 0 # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CE ; 0 # Lo BENGALI LETTER KHANDA TA
+09D7 ; 0 # Mc BENGALI AU LENGTH MARK
+09DC..09DD ; 0 # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; 0 # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E2..09E3 ; 0 # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09E6..09EF ; 0 # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+09F0..09F1 ; 0 # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+09F2..09F3 ; 0 # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+09F4..09F9 ; 0 # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+09FA ; 0 # So BENGALI ISSHAR
+0A01..0A02 ; 0 # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; 0 # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; 0 # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; 0 # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; 0 # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; 0 # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; 0 # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; 0 # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; 0 # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3E..0A40 ; 0 # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; 0 # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; 0 # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4C ; 0 # Mn [2] GURMUKHI VOWEL SIGN OO..GURMUKHI VOWEL SIGN AU
+0A51 ; 0 # Mn GURMUKHI SIGN UDAAT
+0A59..0A5C ; 0 # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; 0 # Lo GURMUKHI LETTER FA
+0A66..0A6F ; 0 # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0A70..0A71 ; 0 # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A72..0A74 ; 0 # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A75 ; 0 # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; 0 # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; 0 # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; 0 # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; 0 # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; 0 # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; 0 # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; 0 # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; 0 # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; 0 # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; 0 # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; 0 # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; 0 # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; 0 # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; 0 # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0AD0 ; 0 # Lo GUJARATI OM
+0AE0..0AE1 ; 0 # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE2..0AE3 ; 0 # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AE6..0AEF ; 0 # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0AF1 ; 0 # Sc GUJARATI RUPEE SIGN
+0B01 ; 0 # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; 0 # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; 0 # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; 0 # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; 0 # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; 0 # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; 0 # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; 0 # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; 0 # Lo ORIYA SIGN AVAGRAHA
+0B3E ; 0 # Mc ORIYA VOWEL SIGN AA
+0B3F ; 0 # Mn ORIYA VOWEL SIGN I
+0B40 ; 0 # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; 0 # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; 0 # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; 0 # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B56 ; 0 # Mn ORIYA AI LENGTH MARK
+0B57 ; 0 # Mc ORIYA AU LENGTH MARK
+0B5C..0B5D ; 0 # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; 0 # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B62..0B63 ; 0 # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B66..0B6F ; 0 # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0B70 ; 0 # So ORIYA ISSHAR
+0B71 ; 0 # Lo ORIYA LETTER WA
+0B82 ; 0 # Mn TAMIL SIGN ANUSVARA
+0B83 ; 0 # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; 0 # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; 0 # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; 0 # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; 0 # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; 0 # Lo TAMIL LETTER JA
+0B9E..0B9F ; 0 # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; 0 # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; 0 # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; 0 # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBE..0BBF ; 0 # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; 0 # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; 0 # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; 0 # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; 0 # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BD0 ; 0 # Lo TAMIL OM
+0BD7 ; 0 # Mc TAMIL AU LENGTH MARK
+0BE6..0BEF ; 0 # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0BF0..0BF2 ; 0 # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+0BF3..0BF8 ; 0 # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+0BF9 ; 0 # Sc TAMIL RUPEE SIGN
+0BFA ; 0 # So TAMIL NUMBER SIGN
+0C01..0C03 ; 0 # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; 0 # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; 0 # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; 0 # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C33 ; 0 # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA
+0C35..0C39 ; 0 # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA
+0C3D ; 0 # Lo TELUGU SIGN AVAGRAHA
+0C3E..0C40 ; 0 # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; 0 # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; 0 # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4C ; 0 # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU
+0C58..0C59 ; 0 # Lo [2] TELUGU LETTER TSA..TELUGU LETTER DZA
+0C60..0C61 ; 0 # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C62..0C63 ; 0 # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C66..0C6F ; 0 # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0C78..0C7E ; 0 # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+0C7F ; 0 # So TELUGU SIGN TUUMU
+0C82..0C83 ; 0 # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; 0 # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; 0 # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; 0 # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; 0 # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; 0 # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; 0 # Lo KANNADA SIGN AVAGRAHA
+0CBE ; 0 # Mc KANNADA VOWEL SIGN AA
+0CBF ; 0 # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; 0 # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; 0 # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; 0 # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; 0 # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC ; 0 # Mn KANNADA VOWEL SIGN AU
+0CD5..0CD6 ; 0 # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CDE ; 0 # Lo KANNADA LETTER FA
+0CE0..0CE1 ; 0 # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE2..0CE3 ; 0 # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CE6..0CEF ; 0 # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0CF1..0CF2 ; 0 # So [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D02..0D03 ; 0 # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; 0 # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; 0 # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D28 ; 0 # Lo [23] MALAYALAM LETTER O..MALAYALAM LETTER NA
+0D2A..0D39 ; 0 # Lo [16] MALAYALAM LETTER PA..MALAYALAM LETTER HA
+0D3D ; 0 # Lo MALAYALAM SIGN AVAGRAHA
+0D3E..0D40 ; 0 # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; 0 # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; 0 # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; 0 # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D57 ; 0 # Mc MALAYALAM AU LENGTH MARK
+0D60..0D61 ; 0 # Lo [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL
+0D62..0D63 ; 0 # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D66..0D6F ; 0 # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0D70..0D75 ; 0 # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS
+0D79 ; 0 # So MALAYALAM DATE MARK
+0D7A..0D7F ; 0 # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D82..0D83 ; 0 # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; 0 # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; 0 # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; 0 # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; 0 # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; 0 # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DCF..0DD1 ; 0 # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; 0 # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; 0 # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; 0 # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DF2..0DF3 ; 0 # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0DF4 ; 0 # Po SINHALA PUNCTUATION KUNDDALIYA
+0E01..0E30 ; 0 # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E31 ; 0 # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; 0 # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E37 ; 0 # Mn [4] THAI CHARACTER SARA I..THAI CHARACTER SARA UEE
+0E3F ; 0 # Sc THAI CURRENCY SYMBOL BAHT
+0E40..0E45 ; 0 # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; 0 # Lm THAI CHARACTER MAIYAMOK
+0E47 ; 0 # Mn THAI CHARACTER MAITAIKHU
+0E4C..0E4E ; 0 # Mn [3] THAI CHARACTER THANTHAKHAT..THAI CHARACTER YAMAKKAN
+0E4F ; 0 # Po THAI CHARACTER FONGMAN
+0E50..0E59 ; 0 # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0E5A..0E5B ; 0 # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+0E81..0E82 ; 0 # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; 0 # Lo LAO LETTER KHO TAM
+0E87..0E88 ; 0 # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; 0 # Lo LAO LETTER SO TAM
+0E8D ; 0 # Lo LAO LETTER NYO
+0E94..0E97 ; 0 # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; 0 # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; 0 # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; 0 # Lo LAO LETTER LO LOOT
+0EA7 ; 0 # Lo LAO LETTER WO
+0EAA..0EAB ; 0 # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; 0 # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB1 ; 0 # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; 0 # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB7 ; 0 # Mn [4] LAO VOWEL SIGN I..LAO VOWEL SIGN YY
+0EBB..0EBC ; 0 # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EBD ; 0 # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; 0 # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; 0 # Lm LAO KO LA
+0ECC..0ECD ; 0 # Mn [2] LAO CANCELLATION MARK..LAO NIGGAHITA
+0ED0..0ED9 ; 0 # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0EDC..0EDD ; 0 # Lo [2] LAO HO NO..LAO HO MO
+0F00 ; 0 # Lo TIBETAN SYLLABLE OM
+0F01..0F03 ; 0 # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+0F04..0F12 ; 0 # Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+0F13..0F17 ; 0 # So [5] TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+0F1A..0F1F ; 0 # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+0F20..0F29 ; 0 # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+0F2A..0F33 ; 0 # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+0F34 ; 0 # So TIBETAN MARK BSDUS RTAGS
+0F36 ; 0 # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+0F38 ; 0 # So TIBETAN MARK CHE MGO
+0F3A ; 0 # Ps TIBETAN MARK GUG RTAGS GYON
+0F3B ; 0 # Pe TIBETAN MARK GUG RTAGS GYAS
+0F3C ; 0 # Ps TIBETAN MARK ANG KHANG GYON
+0F3D ; 0 # Pe TIBETAN MARK ANG KHANG GYAS
+0F3E..0F3F ; 0 # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F40..0F47 ; 0 # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; 0 # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F73 ; 0 # Mn TIBETAN VOWEL SIGN II
+0F75..0F79 ; 0 # Mn [5] TIBETAN VOWEL SIGN UU..TIBETAN VOWEL SIGN VOCALIC LL
+0F7E ; 0 # Mn TIBETAN SIGN RJES SU NGA RO
+0F7F ; 0 # Mc TIBETAN SIGN RNAM BCAD
+0F81 ; 0 # Mn TIBETAN VOWEL SIGN REVERSED II
+0F85 ; 0 # Po TIBETAN MARK PALUTA
+0F88..0F8B ; 0 # Lo [4] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN GRU MED RGYINGS
+0F90..0F97 ; 0 # Mn [8] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; 0 # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FBE..0FC5 ; 0 # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+0FC7..0FCC ; 0 # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+0FCE..0FCF ; 0 # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+0FD0..0FD4 ; 0 # Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+1000..102A ; 0 # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; 0 # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; 0 # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; 0 # Mc MYANMAR VOWEL SIGN E
+1032..1036 ; 0 # Mn [5] MYANMAR VOWEL SIGN AI..MYANMAR SIGN ANUSVARA
+1038 ; 0 # Mc MYANMAR SIGN VISARGA
+103B..103C ; 0 # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; 0 # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+103F ; 0 # Lo MYANMAR LETTER GREAT SA
+1040..1049 ; 0 # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+104A..104F ; 0 # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+1050..1055 ; 0 # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; 0 # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; 0 # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105A..105D ; 0 # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+105E..1060 ; 0 # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1061 ; 0 # Lo MYANMAR LETTER SGAW KAREN SHA
+1062..1064 ; 0 # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1065..1066 ; 0 # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..106D ; 0 # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+106E..1070 ; 0 # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1071..1074 ; 0 # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1075..1081 ; 0 # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1082 ; 0 # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; 0 # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; 0 # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+1087..108C ; 0 # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108E ; 0 # Lo MYANMAR LETTER RUMAI PALAUNG FA
+108F ; 0 # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+1090..1099 ; 0 # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+109E..109F ; 0 # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+10A0..10C5 ; 0 # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10D0..10FA ; 0 # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FB ; 0 # Po GEORGIAN PARAGRAPH SEPARATOR
+10FC ; 0 # Lm MODIFIER LETTER GEORGIAN NAR
+1100..1159 ; 0 # Lo [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH
+115F..11A2 ; 0 # Lo [68] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG SSANGARAEA
+11A8..11F9 ; 0 # Lo [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH
+1200..1248 ; 0 # Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+124A..124D ; 0 # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; 0 # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; 0 # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; 0 # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; 0 # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; 0 # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; 0 # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; 0 # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; 0 # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; 0 # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; 0 # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; 0 # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; 0 # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; 0 # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; 0 # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1360 ; 0 # So ETHIOPIC SECTION MARK
+1361..1368 ; 0 # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR
+1369..137C ; 0 # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+1380..138F ; 0 # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+1390..1399 ; 0 # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+13A0..13F4 ; 0 # Lo [85] CHEROKEE LETTER A..CHEROKEE LETTER YV
+1401..166C ; 0 # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166D..166E ; 0 # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP
+166F..1676 ; 0 # Lo [8] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA
+1680 ; 0 # Zs OGHAM SPACE MARK
+1681..169A ; 0 # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+169B ; 0 # Ps OGHAM FEATHER MARK
+169C ; 0 # Pe OGHAM REVERSED FEATHER MARK
+16A0..16EA ; 0 # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EB..16ED ; 0 # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+16EE..16F0 ; 0 # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+1700..170C ; 0 # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; 0 # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1712..1713 ; 0 # Mn [2] TAGALOG VOWEL SIGN I..TAGALOG VOWEL SIGN U
+1720..1731 ; 0 # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1732..1733 ; 0 # Mn [2] HANUNOO VOWEL SIGN I..HANUNOO VOWEL SIGN U
+1735..1736 ; 0 # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+1740..1751 ; 0 # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1752..1753 ; 0 # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1760..176C ; 0 # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; 0 # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1772..1773 ; 0 # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+1780..17B3 ; 0 # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B4..17B5 ; 0 # Cf [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B6 ; 0 # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; 0 # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; 0 # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; 0 # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; 0 # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17C9..17D1 ; 0 # Mn [9] KHMER SIGN MUUSIKATOAN..KHMER SIGN VIRIAM
+17D3 ; 0 # Mn KHMER SIGN BATHAMASAT
+17D4..17D6 ; 0 # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+17D7 ; 0 # Lm KHMER SIGN LEK TOO
+17D8..17DA ; 0 # Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+17DB ; 0 # Sc KHMER CURRENCY SYMBOL RIEL
+17DC ; 0 # Lo KHMER SIGN AVAKRAHASANYA
+17E0..17E9 ; 0 # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+17F0..17F9 ; 0 # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+1800..1805 ; 0 # Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS
+1806 ; 0 # Pd MONGOLIAN TODO SOFT HYPHEN
+1807..180A ; 0 # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+180B..180D ; 0 # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180E ; 0 # Zs MONGOLIAN VOWEL SEPARATOR
+1810..1819 ; 0 # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1820..1842 ; 0 # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; 0 # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; 0 # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..18A8 ; 0 # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; 0 # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+1900..191C ; 0 # Lo [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA
+1920..1922 ; 0 # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; 0 # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; 0 # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; 0 # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; 0 # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; 0 # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; 0 # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1940 ; 0 # So LIMBU SIGN LOO
+1944..1945 ; 0 # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+1946..194F ; 0 # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+1950..196D ; 0 # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; 0 # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19A9 ; 0 # Lo [42] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW XVA
+19B0..19C0 ; 0 # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY
+19C1..19C7 ; 0 # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B
+19C8..19C9 ; 0 # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2
+19D0..19D9 ; 0 # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+19DE..19DF ; 0 # Po [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+19E0..19FF ; 0 # So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+1A00..1A16 ; 0 # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A19..1A1B ; 0 # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
+1A1E..1A1F ; 0 # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+1B00..1B03 ; 0 # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; 0 # Mc BALINESE SIGN BISAH
+1B05..1B33 ; 0 # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B35 ; 0 # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; 0 # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; 0 # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; 0 # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; 0 # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; 0 # Mn BALINESE VOWEL SIGN PEPET
+1B43 ; 0 # Mc BALINESE VOWEL SIGN PEPET TEDUNG
+1B45..1B4B ; 0 # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B50..1B59 ; 0 # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1B5A..1B60 ; 0 # Po [7] BALINESE PANTI..BALINESE PAMENENG
+1B61..1B6A ; 0 # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+1B74..1B7C ; 0 # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+1B80..1B81 ; 0 # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; 0 # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; 0 # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; 0 # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; 0 # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; 0 # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; 0 # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAE..1BAF ; 0 # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BB0..1BB9 ; 0 # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1C00..1C23 ; 0 # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; 0 # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; 0 # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; 0 # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C36 ; 0 # Mn LEPCHA SIGN RAN
+1C3B..1C3F ; 0 # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+1C40..1C49 ; 0 # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C4D..1C4F ; 0 # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C50..1C59 ; 0 # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+1C5A..1C77 ; 0 # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; 0 # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C7E..1C7F ; 0 # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+1D00..1D2B ; 0 # L& [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D2C..1D61 ; 0 # Lm [54] MODIFIER LETTER CAPITAL A..MODIFIER LETTER SMALL CHI
+1D62..1D77 ; 0 # L& [22] LATIN SUBSCRIPT SMALL LETTER I..LATIN SMALL LETTER TURNED G
+1D78 ; 0 # Lm MODIFIER LETTER CYRILLIC EN
+1D79..1D9A ; 0 # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBF ; 0 # Lm [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+1E00..1F15 ; 0 # L& [278] LATIN CAPITAL LETTER A WITH RING BELOW..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; 0 # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; 0 # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; 0 # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; 0 # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; 0 # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; 0 # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; 0 # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; 0 # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; 0 # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; 0 # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBD ; 0 # Sk GREEK KORONIS
+1FBE ; 0 # L& GREEK PROSGEGRAMMENI
+1FBF..1FC1 ; 0 # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+1FC2..1FC4 ; 0 # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; 0 # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCD..1FCF ; 0 # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+1FD0..1FD3 ; 0 # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; 0 # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FDD..1FDF ; 0 # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+1FE0..1FEC ; 0 # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FED..1FEF ; 0 # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+1FF2..1FF4 ; 0 # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; 0 # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFD..1FFE ; 0 # Sk [2] GREEK OXIA..GREEK DASIA
+2000..200A ; 0 # Zs [11] EN QUAD..HAIR SPACE
+200B..200F ; 0 # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+2010..2015 ; 0 # Pd [6] HYPHEN..HORIZONTAL BAR
+2016..2017 ; 0 # Po [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE
+2018 ; 0 # Pi LEFT SINGLE QUOTATION MARK
+2019 ; 0 # Pf RIGHT SINGLE QUOTATION MARK
+201A ; 0 # Ps SINGLE LOW-9 QUOTATION MARK
+201B..201C ; 0 # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK
+201D ; 0 # Pf RIGHT DOUBLE QUOTATION MARK
+201E ; 0 # Ps DOUBLE LOW-9 QUOTATION MARK
+201F ; 0 # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+2020..2027 ; 0 # Po [8] DAGGER..HYPHENATION POINT
+2028 ; 0 # Zl LINE SEPARATOR
+2029 ; 0 # Zp PARAGRAPH SEPARATOR
+202A..202E ; 0 # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+202F ; 0 # Zs NARROW NO-BREAK SPACE
+2030..2038 ; 0 # Po [9] PER MILLE SIGN..CARET
+2039 ; 0 # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+203A ; 0 # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+203B..203E ; 0 # Po [4] REFERENCE MARK..OVERLINE
+203F..2040 ; 0 # Pc [2] UNDERTIE..CHARACTER TIE
+2041..2043 ; 0 # Po [3] CARET INSERTION POINT..HYPHEN BULLET
+2044 ; 0 # Sm FRACTION SLASH
+2045 ; 0 # Ps LEFT SQUARE BRACKET WITH QUILL
+2046 ; 0 # Pe RIGHT SQUARE BRACKET WITH QUILL
+2047..2051 ; 0 # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+2052 ; 0 # Sm COMMERCIAL MINUS SIGN
+2053 ; 0 # Po SWUNG DASH
+2054 ; 0 # Pc INVERTED UNDERTIE
+2055..205E ; 0 # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+205F ; 0 # Zs MEDIUM MATHEMATICAL SPACE
+2060..2064 ; 0 # Cf [5] WORD JOINER..INVISIBLE PLUS
+206A..206F ; 0 # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES
+2070 ; 0 # No SUPERSCRIPT ZERO
+2071 ; 0 # L& SUPERSCRIPT LATIN SMALL LETTER I
+2074..2079 ; 0 # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE
+207A..207C ; 0 # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+207D ; 0 # Ps SUPERSCRIPT LEFT PARENTHESIS
+207E ; 0 # Pe SUPERSCRIPT RIGHT PARENTHESIS
+207F ; 0 # L& SUPERSCRIPT LATIN SMALL LETTER N
+2080..2089 ; 0 # No [10] SUBSCRIPT ZERO..SUBSCRIPT NINE
+208A..208C ; 0 # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+208D ; 0 # Ps SUBSCRIPT LEFT PARENTHESIS
+208E ; 0 # Pe SUBSCRIPT RIGHT PARENTHESIS
+2090..2094 ; 0 # Lm [5] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER SCHWA
+20A0..20B5 ; 0 # Sc [22] EURO-CURRENCY SIGN..CEDI SIGN
+20DD..20E0 ; 0 # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E2..20E4 ; 0 # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+2100..2101 ; 0 # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+2102 ; 0 # L& DOUBLE-STRUCK CAPITAL C
+2103..2106 ; 0 # So [4] DEGREE CELSIUS..CADA UNA
+2107 ; 0 # L& EULER CONSTANT
+2108..2109 ; 0 # So [2] SCRUPLE..DEGREE FAHRENHEIT
+210A..2113 ; 0 # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2114 ; 0 # So L B BAR SYMBOL
+2115 ; 0 # L& DOUBLE-STRUCK CAPITAL N
+2116..2118 ; 0 # So [3] NUMERO SIGN..SCRIPT CAPITAL P
+2119..211D ; 0 # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+211E..2123 ; 0 # So [6] PRESCRIPTION TAKE..VERSICLE
+2124 ; 0 # L& DOUBLE-STRUCK CAPITAL Z
+2125 ; 0 # So OUNCE SIGN
+2126 ; 0 # L& OHM SIGN
+2127 ; 0 # So INVERTED OHM SIGN
+2128 ; 0 # L& BLACK-LETTER CAPITAL Z
+2129 ; 0 # So TURNED GREEK SMALL LETTER IOTA
+212A..212D ; 0 # L& [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+212E ; 0 # So ESTIMATED SYMBOL
+212F..2134 ; 0 # L& [6] SCRIPT SMALL E..SCRIPT SMALL O
+2135..2138 ; 0 # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; 0 # L& INFORMATION SOURCE
+213A..213B ; 0 # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+213C..213F ; 0 # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2140..2144 ; 0 # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+2145..2149 ; 0 # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214A ; 0 # So PROPERTY LINE
+214B ; 0 # Sm TURNED AMPERSAND
+214C..214D ; 0 # So [2] PER SIGN..AKTIESELSKAB
+214E ; 0 # L& TURNED SMALL F
+214F ; 0 # So SYMBOL FOR SAMARITAN SOURCE
+2153..215F ; 0 # No [13] VULGAR FRACTION ONE THIRD..FRACTION NUMERATOR ONE
+2160..2182 ; 0 # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; 0 # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; 0 # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2190..2194 ; 0 # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+2195..2199 ; 0 # So [5] UP DOWN ARROW..SOUTH WEST ARROW
+219A..219B ; 0 # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+219C..219F ; 0 # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+21A0 ; 0 # Sm RIGHTWARDS TWO HEADED ARROW
+21A1..21A2 ; 0 # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+21A3 ; 0 # Sm RIGHTWARDS ARROW WITH TAIL
+21A4..21A5 ; 0 # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+21A6 ; 0 # Sm RIGHTWARDS ARROW FROM BAR
+21A7..21AD ; 0 # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+21AE ; 0 # Sm LEFT RIGHT ARROW WITH STROKE
+21AF..21CD ; 0 # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+21CE..21CF ; 0 # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+21D0..21D1 ; 0 # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+21D2 ; 0 # Sm RIGHTWARDS DOUBLE ARROW
+21D3 ; 0 # So DOWNWARDS DOUBLE ARROW
+21D4 ; 0 # Sm LEFT RIGHT DOUBLE ARROW
+21D5..21F3 ; 0 # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
+21F4..22FF ; 0 # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
+2300..2307 ; 0 # So [8] DIAMETER SIGN..WAVY LINE
+2308..230B ; 0 # Sm [4] LEFT CEILING..RIGHT FLOOR
+230C..231F ; 0 # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
+2320..2321 ; 0 # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+2322..2328 ; 0 # So [7] FROWN..KEYBOARD
+2329 ; 0 # Ps LEFT-POINTING ANGLE BRACKET
+232A ; 0 # Pe RIGHT-POINTING ANGLE BRACKET
+232B..237B ; 0 # So [81] ERASE TO THE LEFT..NOT CHECK MARK
+237C ; 0 # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+237D..239A ; 0 # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+239B..23B3 ; 0 # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+23B4..23DB ; 0 # So [40] TOP SQUARE BRACKET..FUSE
+23DC..23E1 ; 0 # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+23E2..23E7 ; 0 # So [6] WHITE TRAPEZIUM..ELECTRICAL INTERSECTION
+2400..2426 ; 0 # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+2440..244A ; 0 # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
+2460..249B ; 0 # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+249C..24E9 ; 0 # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+24EA..24FF ; 0 # No [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO
+2500..25B6 ; 0 # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE
+25B7 ; 0 # Sm WHITE RIGHT-POINTING TRIANGLE
+25B8..25C0 ; 0 # So [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE
+25C1 ; 0 # Sm WHITE LEFT-POINTING TRIANGLE
+25C2..25F7 ; 0 # So [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+25F8..25FF ; 0 # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+2600..266E ; 0 # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
+266F ; 0 # Sm MUSIC SHARP SIGN
+2670..269D ; 0 # So [46] WEST SYRIAC CROSS..OUTLINED WHITE STAR
+26A0..26BC ; 0 # So [29] WARNING SIGN..SESQUIQUADRATE
+26C0..26C3 ; 0 # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+2701..2704 ; 0 # So [4] UPPER BLADE SCISSORS..WHITE SCISSORS
+2706..2709 ; 0 # So [4] TELEPHONE LOCATION SIGN..ENVELOPE
+270C..2727 ; 0 # So [28] VICTORY HAND..WHITE FOUR POINTED STAR
+2729..274B ; 0 # So [35] STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+274D ; 0 # So SHADOWED WHITE CIRCLE
+274F..2752 ; 0 # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE
+2756 ; 0 # So BLACK DIAMOND MINUS WHITE X
+2758..275E ; 0 # So [7] LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
+2761..2767 ; 0 # So [7] CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET
+2768 ; 0 # Ps MEDIUM LEFT PARENTHESIS ORNAMENT
+2769 ; 0 # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
+276A ; 0 # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+276B ; 0 # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+276C ; 0 # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+276D ; 0 # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+276E ; 0 # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+276F ; 0 # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+2770 ; 0 # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+2771 ; 0 # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+2772 ; 0 # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+2773 ; 0 # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+2774 ; 0 # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT
+2775 ; 0 # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT
+2776..2793 ; 0 # No [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+2794 ; 0 # So HEAVY WIDE-HEADED RIGHTWARDS ARROW
+2798..27AF ; 0 # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+27B1..27BE ; 0 # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW
+27C0..27C4 ; 0 # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+27C5 ; 0 # Ps LEFT S-SHAPED BAG DELIMITER
+27C6 ; 0 # Pe RIGHT S-SHAPED BAG DELIMITER
+27C7..27CA ; 0 # Sm [4] OR WITH DOT INSIDE..VERTICAL BAR WITH HORIZONTAL STROKE
+27CC ; 0 # Sm LONG DIVISION
+27D0..27E5 ; 0 # Sm [22] WHITE DIAMOND WITH CENTRED DOT..WHITE SQUARE WITH RIGHTWARDS TICK
+27E6 ; 0 # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+27E7 ; 0 # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+27E8 ; 0 # Ps MATHEMATICAL LEFT ANGLE BRACKET
+27E9 ; 0 # Pe MATHEMATICAL RIGHT ANGLE BRACKET
+27EA ; 0 # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+27EB ; 0 # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+27EC ; 0 # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+27ED ; 0 # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+27EE ; 0 # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+27EF ; 0 # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+27F0..27FF ; 0 # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+2800..28FF ; 0 # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+2900..2982 ; 0 # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON
+2983 ; 0 # Ps LEFT WHITE CURLY BRACKET
+2984 ; 0 # Pe RIGHT WHITE CURLY BRACKET
+2985 ; 0 # Ps LEFT WHITE PARENTHESIS
+2986 ; 0 # Pe RIGHT WHITE PARENTHESIS
+2987 ; 0 # Ps Z NOTATION LEFT IMAGE BRACKET
+2988 ; 0 # Pe Z NOTATION RIGHT IMAGE BRACKET
+2989 ; 0 # Ps Z NOTATION LEFT BINDING BRACKET
+298A ; 0 # Pe Z NOTATION RIGHT BINDING BRACKET
+298B ; 0 # Ps LEFT SQUARE BRACKET WITH UNDERBAR
+298C ; 0 # Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+298D ; 0 # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+298E ; 0 # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+298F ; 0 # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2990 ; 0 # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+2991 ; 0 # Ps LEFT ANGLE BRACKET WITH DOT
+2992 ; 0 # Pe RIGHT ANGLE BRACKET WITH DOT
+2993 ; 0 # Ps LEFT ARC LESS-THAN BRACKET
+2994 ; 0 # Pe RIGHT ARC GREATER-THAN BRACKET
+2995 ; 0 # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+2996 ; 0 # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+2997 ; 0 # Ps LEFT BLACK TORTOISE SHELL BRACKET
+2998 ; 0 # Pe RIGHT BLACK TORTOISE SHELL BRACKET
+2999..29D7 ; 0 # Sm [63] DOTTED FENCE..BLACK HOURGLASS
+29D8 ; 0 # Ps LEFT WIGGLY FENCE
+29D9 ; 0 # Pe RIGHT WIGGLY FENCE
+29DA ; 0 # Ps LEFT DOUBLE WIGGLY FENCE
+29DB ; 0 # Pe RIGHT DOUBLE WIGGLY FENCE
+29DC..29FB ; 0 # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+29FC ; 0 # Ps LEFT-POINTING CURVED ANGLE BRACKET
+29FD ; 0 # Pe RIGHT-POINTING CURVED ANGLE BRACKET
+29FE..2AFF ; 0 # Sm [258] TINY..N-ARY WHITE VERTICAL BAR
+2B00..2B2F ; 0 # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE
+2B30..2B44 ; 0 # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+2B45..2B46 ; 0 # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+2B47..2B4C ; 0 # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+2B50..2B54 ; 0 # So [5] WHITE MEDIUM STAR..WHITE RIGHT-POINTING PENTAGON
+2C00..2C2E ; 0 # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; 0 # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C60..2C6F ; 0 # L& [16] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN CAPITAL LETTER TURNED A
+2C71..2C7C ; 0 # L& [12] LATIN SMALL LETTER V WITH RIGHT HOOK..LATIN SUBSCRIPT SMALL LETTER J
+2C7D ; 0 # Lm MODIFIER LETTER CAPITAL V
+2C80..2CE4 ; 0 # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI
+2CE5..2CEA ; 0 # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+2CF9..2CFC ; 0 # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+2CFD ; 0 # No COPTIC FRACTION ONE HALF
+2CFE..2CFF ; 0 # Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+2D00..2D25 ; 0 # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+2D30..2D65 ; 0 # Lo [54] TIFINAGH LETTER YA..TIFINAGH LETTER YAZZ
+2D6F ; 0 # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2D80..2D96 ; 0 # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; 0 # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; 0 # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; 0 # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; 0 # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; 0 # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; 0 # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; 0 # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; 0 # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+2E00..2E01 ; 0 # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+2E02 ; 0 # Pi LEFT SUBSTITUTION BRACKET
+2E03 ; 0 # Pf RIGHT SUBSTITUTION BRACKET
+2E04 ; 0 # Pi LEFT DOTTED SUBSTITUTION BRACKET
+2E05 ; 0 # Pf RIGHT DOTTED SUBSTITUTION BRACKET
+2E06..2E08 ; 0 # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+2E09 ; 0 # Pi LEFT TRANSPOSITION BRACKET
+2E0A ; 0 # Pf RIGHT TRANSPOSITION BRACKET
+2E0B ; 0 # Po RAISED SQUARE
+2E0C ; 0 # Pi LEFT RAISED OMISSION BRACKET
+2E0D ; 0 # Pf RIGHT RAISED OMISSION BRACKET
+2E0E..2E16 ; 0 # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+2E17 ; 0 # Pd DOUBLE OBLIQUE HYPHEN
+2E18..2E19 ; 0 # Po [2] INVERTED INTERROBANG..PALM BRANCH
+2E1A ; 0 # Pd HYPHEN WITH DIAERESIS
+2E1B ; 0 # Po TILDE WITH RING ABOVE
+2E1C ; 0 # Pi LEFT LOW PARAPHRASE BRACKET
+2E1D ; 0 # Pf RIGHT LOW PARAPHRASE BRACKET
+2E1E..2E1F ; 0 # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+2E20 ; 0 # Pi LEFT VERTICAL BAR WITH QUILL
+2E21 ; 0 # Pf RIGHT VERTICAL BAR WITH QUILL
+2E22 ; 0 # Ps TOP LEFT HALF BRACKET
+2E23 ; 0 # Pe TOP RIGHT HALF BRACKET
+2E24 ; 0 # Ps BOTTOM LEFT HALF BRACKET
+2E25 ; 0 # Pe BOTTOM RIGHT HALF BRACKET
+2E26 ; 0 # Ps LEFT SIDEWAYS U BRACKET
+2E27 ; 0 # Pe RIGHT SIDEWAYS U BRACKET
+2E28 ; 0 # Ps LEFT DOUBLE PARENTHESIS
+2E29 ; 0 # Pe RIGHT DOUBLE PARENTHESIS
+2E2A..2E2E ; 0 # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+2E2F ; 0 # Lm VERTICAL TILDE
+2E30 ; 0 # Po RING POINT
+2E80..2E99 ; 0 # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+2E9B..2EF3 ; 0 # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+2F00..2FD5 ; 0 # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+2FF0..2FFB ; 0 # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+3000 ; 0 # Zs IDEOGRAPHIC SPACE
+3001..3003 ; 0 # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
+3004 ; 0 # So JAPANESE INDUSTRIAL STANDARD SYMBOL
+3005 ; 0 # Lm IDEOGRAPHIC ITERATION MARK
+3006 ; 0 # Lo IDEOGRAPHIC CLOSING MARK
+3007 ; 0 # Nl IDEOGRAPHIC NUMBER ZERO
+3008 ; 0 # Ps LEFT ANGLE BRACKET
+3009 ; 0 # Pe RIGHT ANGLE BRACKET
+300A ; 0 # Ps LEFT DOUBLE ANGLE BRACKET
+300B ; 0 # Pe RIGHT DOUBLE ANGLE BRACKET
+300C ; 0 # Ps LEFT CORNER BRACKET
+300D ; 0 # Pe RIGHT CORNER BRACKET
+300E ; 0 # Ps LEFT WHITE CORNER BRACKET
+300F ; 0 # Pe RIGHT WHITE CORNER BRACKET
+3010 ; 0 # Ps LEFT BLACK LENTICULAR BRACKET
+3011 ; 0 # Pe RIGHT BLACK LENTICULAR BRACKET
+3012..3013 ; 0 # So [2] POSTAL MARK..GETA MARK
+3014 ; 0 # Ps LEFT TORTOISE SHELL BRACKET
+3015 ; 0 # Pe RIGHT TORTOISE SHELL BRACKET
+3016 ; 0 # Ps LEFT WHITE LENTICULAR BRACKET
+3017 ; 0 # Pe RIGHT WHITE LENTICULAR BRACKET
+3018 ; 0 # Ps LEFT WHITE TORTOISE SHELL BRACKET
+3019 ; 0 # Pe RIGHT WHITE TORTOISE SHELL BRACKET
+301A ; 0 # Ps LEFT WHITE SQUARE BRACKET
+301B ; 0 # Pe RIGHT WHITE SQUARE BRACKET
+301C ; 0 # Pd WAVE DASH
+301D ; 0 # Ps REVERSED DOUBLE PRIME QUOTATION MARK
+301E..301F ; 0 # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+3020 ; 0 # So POSTAL MARK FACE
+3021..3029 ; 0 # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3030 ; 0 # Pd WAVY DASH
+3031..3035 ; 0 # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3036..3037 ; 0 # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+3038..303A ; 0 # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; 0 # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+303C ; 0 # Lo MASU MARK
+303D ; 0 # Po PART ALTERNATION MARK
+303E..303F ; 0 # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
+3041..3096 ; 0 # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309B..309C ; 0 # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+309D..309E ; 0 # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; 0 # Lo HIRAGANA DIGRAPH YORI
+30A0 ; 0 # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+30A1..30FA ; 0 # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FB ; 0 # Po KATAKANA MIDDLE DOT
+30FC..30FE ; 0 # Lm [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+30FF ; 0 # Lo KATAKANA DIGRAPH KOTO
+3105..312D ; 0 # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; 0 # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+3190..3191 ; 0 # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+3192..3195 ; 0 # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+3196..319F ; 0 # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+31A0..31B7 ; 0 # Lo [24] BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H
+31C0..31E3 ; 0 # So [36] CJK STROKE T..CJK STROKE Q
+31F0..31FF ; 0 # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3200..321E ; 0 # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+3220..3229 ; 0 # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+322A..3243 ; 0 # So [26] PARENTHESIZED IDEOGRAPH MOON..PARENTHESIZED IDEOGRAPH REACH
+3250 ; 0 # So PARTNERSHIP SIGN
+3251..325F ; 0 # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+3260..327F ; 0 # So [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+3280..3289 ; 0 # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+328A..32B0 ; 0 # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+32B1..32BF ; 0 # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+32C0..32FE ; 0 # So [63] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..CIRCLED KATAKANA WO
+3300..33FF ; 0 # So [256] SQUARE APAATO..SQUARE GAL
+3400..4DB5 ; 0 # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4DC0..4DFF ; 0 # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+4E00..9FC3 ; 0 # Lo [20932] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FC3
+A000..A014 ; 0 # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; 0 # Lm YI SYLLABLE WU
+A016..A48C ; 0 # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A490..A4C6 ; 0 # So [55] YI RADICAL QOT..YI RADICAL KE
+A500..A60B ; 0 # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; 0 # Lm VAI SYLLABLE LENGTHENER
+A60D..A60F ; 0 # Po [3] VAI COMMA..VAI QUESTION MARK
+A610..A61F ; 0 # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A620..A629 ; 0 # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A62A..A62B ; 0 # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A640..A65F ; 0 # L& [32] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER YN
+A662..A66D ; 0 # L& [12] CYRILLIC CAPITAL LETTER SOFT DE..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; 0 # Lo CYRILLIC LETTER MULTIOCULAR O
+A670..A672 ; 0 # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A673 ; 0 # Po SLAVONIC ASTERISK
+A67E ; 0 # Po CYRILLIC KAVYKA
+A67F ; 0 # Lm CYRILLIC PAYEROK
+A680..A697 ; 0 # L& [24] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER SHWE
+A700..A716 ; 0 # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A717..A71F ; 0 # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A720..A721 ; 0 # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A722..A76F ; 0 # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; 0 # Lm MODIFIER LETTER US
+A771..A787 ; 0 # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A788 ; 0 # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A789..A78A ; 0 # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+A78B..A78C ; 0 # L& [2] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER SALTILLO
+A7FB..A801 ; 0 # Lo [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A802 ; 0 # Mn SYLOTI NAGRI SIGN DVISVARA
+A803..A805 ; 0 # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; 0 # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80B ; 0 # Mn SYLOTI NAGRI SIGN ANUSVARA
+A80C..A822 ; 0 # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; 0 # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; 0 # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; 0 # Mc SYLOTI NAGRI VOWEL SIGN OO
+A828..A82B ; 0 # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+A840..A873 ; 0 # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A874..A877 ; 0 # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+A880..A881 ; 0 # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; 0 # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; 0 # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8CE..A8CF ; 0 # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+A8D0..A8D9 ; 0 # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A900..A909 ; 0 # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A90A..A925 ; 0 # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A926..A92A ; 0 # Mn [5] KAYAH LI VOWEL UE..KAYAH LI VOWEL O
+A92E..A92F ; 0 # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+A930..A946 ; 0 # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A947..A951 ; 0 # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952 ; 0 # Mc REJANG CONSONANT SIGN H
+A95F ; 0 # Po REJANG SECTION MARK
+AA00..AA28 ; 0 # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA29..AA2E ; 0 # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; 0 # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; 0 # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; 0 # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; 0 # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA40..AA42 ; 0 # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA43 ; 0 # Mn CHAM CONSONANT SIGN FINAL NG
+AA44..AA4B ; 0 # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4C ; 0 # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; 0 # Mc CHAM CONSONANT SIGN FINAL H
+AA50..AA59 ; 0 # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+AA5C..AA5F ; 0 # Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+AC00..D7A3 ; 0 # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+E000..F8FF ; 0 # Co [6400] <private-use-E000>..<private-use-F8FF>
+F900..FA2D ; 0 # Lo [302] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA2D
+FA30..FA6A ; 0 # Lo [59] CJK COMPATIBILITY IDEOGRAPH-FA30..CJK COMPATIBILITY IDEOGRAPH-FA6A
+FA70..FAD9 ; 0 # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB00..FB06 ; 0 # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; 0 # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FB1D ; 0 # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; 0 # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB29 ; 0 # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+FB2A..FB36 ; 0 # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; 0 # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; 0 # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; 0 # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; 0 # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; 0 # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; 0 # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD3E ; 0 # Ps ORNATE LEFT PARENTHESIS
+FD3F ; 0 # Pe ORNATE RIGHT PARENTHESIS
+FD50..FD8F ; 0 # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; 0 # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; 0 # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FDFC ; 0 # Sc RIAL SIGN
+FDFD ; 0 # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
+FE00..FE0F ; 0 # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE10..FE16 ; 0 # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+FE17 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+FE18 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+FE19 ; 0 # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+FE30 ; 0 # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+FE31..FE32 ; 0 # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+FE33..FE34 ; 0 # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE35 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+FE36 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+FE37 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+FE38 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+FE39 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+FE3A ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+FE3B ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+FE3C ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+FE3D ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+FE3E ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+FE3F ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+FE40 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+FE41 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+FE42 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+FE43 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+FE44 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+FE45..FE46 ; 0 # Po [2] SESAME DOT..WHITE SESAME DOT
+FE47 ; 0 # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+FE48 ; 0 # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+FE49..FE4C ; 0 # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+FE4D..FE4F ; 0 # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FE50..FE52 ; 0 # Po [3] SMALL COMMA..SMALL FULL STOP
+FE54..FE57 ; 0 # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+FE58 ; 0 # Pd SMALL EM DASH
+FE59 ; 0 # Ps SMALL LEFT PARENTHESIS
+FE5A ; 0 # Pe SMALL RIGHT PARENTHESIS
+FE5B ; 0 # Ps SMALL LEFT CURLY BRACKET
+FE5C ; 0 # Pe SMALL RIGHT CURLY BRACKET
+FE5D ; 0 # Ps SMALL LEFT TORTOISE SHELL BRACKET
+FE5E ; 0 # Pe SMALL RIGHT TORTOISE SHELL BRACKET
+FE5F..FE61 ; 0 # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK
+FE62 ; 0 # Sm SMALL PLUS SIGN
+FE63 ; 0 # Pd SMALL HYPHEN-MINUS
+FE64..FE66 ; 0 # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+FE68 ; 0 # Po SMALL REVERSE SOLIDUS
+FE69 ; 0 # Sc SMALL DOLLAR SIGN
+FE6A..FE6B ; 0 # Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+FE70..FE74 ; 0 # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; 0 # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FEFF ; 0 # Cf ZERO WIDTH NO-BREAK SPACE
+FF01..FF03 ; 0 # Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+FF04 ; 0 # Sc FULLWIDTH DOLLAR SIGN
+FF05..FF07 ; 0 # Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+FF08 ; 0 # Ps FULLWIDTH LEFT PARENTHESIS
+FF09 ; 0 # Pe FULLWIDTH RIGHT PARENTHESIS
+FF0A ; 0 # Po FULLWIDTH ASTERISK
+FF0B ; 0 # Sm FULLWIDTH PLUS SIGN
+FF0C ; 0 # Po FULLWIDTH COMMA
+FF0D ; 0 # Pd FULLWIDTH HYPHEN-MINUS
+FF0E..FF0F ; 0 # Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+FF10..FF19 ; 0 # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+FF1A..FF1B ; 0 # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+FF1C..FF1E ; 0 # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+FF1F..FF20 ; 0 # Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+FF21..FF3A ; 0 # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF3B ; 0 # Ps FULLWIDTH LEFT SQUARE BRACKET
+FF3C ; 0 # Po FULLWIDTH REVERSE SOLIDUS
+FF3D ; 0 # Pe FULLWIDTH RIGHT SQUARE BRACKET
+FF3E ; 0 # Sk FULLWIDTH CIRCUMFLEX ACCENT
+FF3F ; 0 # Pc FULLWIDTH LOW LINE
+FF40 ; 0 # Sk FULLWIDTH GRAVE ACCENT
+FF41..FF5A ; 0 # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+FF5B ; 0 # Ps FULLWIDTH LEFT CURLY BRACKET
+FF5C ; 0 # Sm FULLWIDTH VERTICAL LINE
+FF5D ; 0 # Pe FULLWIDTH RIGHT CURLY BRACKET
+FF5E ; 0 # Sm FULLWIDTH TILDE
+FF5F ; 0 # Ps FULLWIDTH LEFT WHITE PARENTHESIS
+FF60 ; 0 # Pe FULLWIDTH RIGHT WHITE PARENTHESIS
+FF61 ; 0 # Po HALFWIDTH IDEOGRAPHIC FULL STOP
+FF62 ; 0 # Ps HALFWIDTH LEFT CORNER BRACKET
+FF63 ; 0 # Pe HALFWIDTH RIGHT CORNER BRACKET
+FF64..FF65 ; 0 # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+FF66..FF6F ; 0 # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF70 ; 0 # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF71..FF9D ; 0 # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FF9E..FF9F ; 0 # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFA0..FFBE ; 0 # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; 0 # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; 0 # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; 0 # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; 0 # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+FFE0..FFE1 ; 0 # Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+FFE2 ; 0 # Sm FULLWIDTH NOT SIGN
+FFE3 ; 0 # Sk FULLWIDTH MACRON
+FFE4 ; 0 # So FULLWIDTH BROKEN BAR
+FFE5..FFE6 ; 0 # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+FFE8 ; 0 # So HALFWIDTH FORMS LIGHT VERTICAL
+FFE9..FFEC ; 0 # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+FFED..FFEE ; 0 # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+FFF9..FFFB ; 0 # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+FFFC..FFFD ; 0 # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER
+10000..1000B ; 0 # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; 0 # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; 0 # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; 0 # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; 0 # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; 0 # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; 0 # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10100..10101 ; 0 # Po [2] AEGEAN WORD SEPARATOR LINE..AEGEAN WORD SEPARATOR DOT
+10102 ; 0 # So AEGEAN CHECK MARK
+10107..10133 ; 0 # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+10137..1013F ; 0 # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+10140..10174 ; 0 # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10175..10178 ; 0 # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+10179..10189 ; 0 # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+1018A ; 0 # No GREEK ZERO SIGN
+10190..1019B ; 0 # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
+101D0..101FC ; 0 # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+10280..1029C ; 0 # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; 0 # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031E ; 0 # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU
+10320..10323 ; 0 # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+10330..10340 ; 0 # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; 0 # Nl GOTHIC LETTER NINETY
+10342..10349 ; 0 # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; 0 # Nl GOTHIC LETTER NINE HUNDRED
+10380..1039D ; 0 # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+1039F ; 0 # Po UGARITIC WORD DIVIDER
+103A0..103C3 ; 0 # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; 0 # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D0 ; 0 # Po OLD PERSIAN WORD DIVIDER
+103D1..103D5 ; 0 # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+10400..1044F ; 0 # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+10450..1049D ; 0 # Lo [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+104A0..104A9 ; 0 # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+10800..10805 ; 0 # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; 0 # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; 0 # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; 0 # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; 0 # Lo CYPRIOT SYLLABLE ZA
+1083F ; 0 # Lo CYPRIOT SYLLABLE ZO
+10900..10915 ; 0 # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10916..10919 ; 0 # No [4] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER ONE HUNDRED
+1091F ; 0 # Po PHOENICIAN WORD SEPARATOR
+10920..10939 ; 0 # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+1093F ; 0 # Po LYDIAN TRIANGULAR MARK
+10A00 ; 0 # Lo KHAROSHTHI LETTER A
+10A01..10A03 ; 0 # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; 0 # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C ; 0 # Mn KHAROSHTHI VOWEL LENGTH MARK
+10A0E ; 0 # Mn KHAROSHTHI SIGN ANUSVARA
+10A10..10A13 ; 0 # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; 0 # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; 0 # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A40..10A47 ; 0 # No [8] KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND
+10A50..10A58 ; 0 # Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+12000..1236E ; 0 # Lo [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM
+12400..12462 ; 0 # Nl [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER
+12470..12473 ; 0 # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON
+1D000..1D0F5 ; 0 # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+1D100..1D126 ; 0 # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+1D129..1D164 ; 0 # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+1D16A..1D16C ; 0 # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+1D173..1D17A ; 0 # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+1D183..1D184 ; 0 # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+1D18C..1D1A9 ; 0 # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+1D1AE..1D1DD ; 0 # So [48] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL PES SUBPUNCTIS
+1D200..1D241 ; 0 # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+1D245 ; 0 # So GREEK MUSICAL LEIMMA
+1D300..1D356 ; 0 # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+1D360..1D371 ; 0 # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE
+1D400..1D454 ; 0 # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; 0 # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; 0 # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; 0 # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; 0 # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; 0 # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; 0 # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; 0 # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; 0 # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; 0 # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; 0 # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; 0 # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; 0 # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; 0 # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; 0 # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; 0 # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; 0 # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; 0 # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; 0 # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; 0 # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C1 ; 0 # Sm MATHEMATICAL BOLD NABLA
+1D6C2..1D6DA ; 0 # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DB ; 0 # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+1D6DC..1D6FA ; 0 # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FB ; 0 # Sm MATHEMATICAL ITALIC NABLA
+1D6FC..1D714 ; 0 # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D715 ; 0 # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+1D716..1D734 ; 0 # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D735 ; 0 # Sm MATHEMATICAL BOLD ITALIC NABLA
+1D736..1D74E ; 0 # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D74F ; 0 # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+1D750..1D76E ; 0 # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D76F ; 0 # Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+1D770..1D788 ; 0 # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D789 ; 0 # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+1D78A..1D7A8 ; 0 # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7A9 ; 0 # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+1D7AA..1D7C2 ; 0 # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C3 ; 0 # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+1D7C4..1D7CB ; 0 # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; 0 # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1F000..1F02B ; 0 # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F030..1F093 ; 0 # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+20000..2A6D6 ; 0 # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2F800..2FA1D ; 0 # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+E0001 ; 0 # Cf LANGUAGE TAG
+E0020..E007F ; 0 # Cf [96] TAG SPACE..CANCEL TAG
+E0100..E01EF ; 0 # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+F0000..FFFFD ; 0 # Co [65534] <private-use-F0000>..<private-use-FFFFD>
+100000..10FFFD; 0 # Co [65534] <private-use-100000>..<private-use-10FFFD>
+
+# The above property value applies to 875931 code points not listed here.
+# Total code points: 1113611
+
+# ================================================
+
+# Canonical_Combining_Class=Overlay
+
+0334..0338 ; 1 # Mn [5] COMBINING TILDE OVERLAY..COMBINING LONG SOLIDUS OVERLAY
+20D2..20D3 ; 1 # Mn [2] COMBINING LONG VERTICAL LINE OVERLAY..COMBINING SHORT VERTICAL LINE OVERLAY
+20D8..20DA ; 1 # Mn [3] COMBINING RING OVERLAY..COMBINING ANTICLOCKWISE RING OVERLAY
+20E5..20E6 ; 1 # Mn [2] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING DOUBLE VERTICAL STROKE OVERLAY
+20EA..20EB ; 1 # Mn [2] COMBINING LEFTWARDS ARROW OVERLAY..COMBINING LONG DOUBLE SOLIDUS OVERLAY
+10A39 ; 1 # Mn KHAROSHTHI SIGN CAUDA
+1D167..1D169 ; 1 # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+
+# Total code points: 18
+
+# ================================================
+
+# Canonical_Combining_Class=Nukta
+
+093C ; 7 # Mn DEVANAGARI SIGN NUKTA
+09BC ; 7 # Mn BENGALI SIGN NUKTA
+0A3C ; 7 # Mn GURMUKHI SIGN NUKTA
+0ABC ; 7 # Mn GUJARATI SIGN NUKTA
+0B3C ; 7 # Mn ORIYA SIGN NUKTA
+0CBC ; 7 # Mn KANNADA SIGN NUKTA
+1037 ; 7 # Mn MYANMAR SIGN DOT BELOW
+1B34 ; 7 # Mn BALINESE SIGN REREKAN
+1C37 ; 7 # Mn LEPCHA SIGN NUKTA
+
+# Total code points: 9
+
+# ================================================
+
+# Canonical_Combining_Class=Kana_Voicing
+
+3099..309A ; 8 # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=Virama
+
+094D ; 9 # Mn DEVANAGARI SIGN VIRAMA
+09CD ; 9 # Mn BENGALI SIGN VIRAMA
+0A4D ; 9 # Mn GURMUKHI SIGN VIRAMA
+0ACD ; 9 # Mn GUJARATI SIGN VIRAMA
+0B4D ; 9 # Mn ORIYA SIGN VIRAMA
+0BCD ; 9 # Mn TAMIL SIGN VIRAMA
+0C4D ; 9 # Mn TELUGU SIGN VIRAMA
+0CCD ; 9 # Mn KANNADA SIGN VIRAMA
+0D4D ; 9 # Mn MALAYALAM SIGN VIRAMA
+0DCA ; 9 # Mn SINHALA SIGN AL-LAKUNA
+0E3A ; 9 # Mn THAI CHARACTER PHINTHU
+0F84 ; 9 # Mn TIBETAN MARK HALANTA
+1039..103A ; 9 # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+1714 ; 9 # Mn TAGALOG SIGN VIRAMA
+1734 ; 9 # Mn HANUNOO SIGN PAMUDPOD
+17D2 ; 9 # Mn KHMER SIGN COENG
+1B44 ; 9 # Mc BALINESE ADEG ADEG
+1BAA ; 9 # Mc SUNDANESE SIGN PAMAAEH
+A806 ; 9 # Mn SYLOTI NAGRI SIGN HASANTA
+A8C4 ; 9 # Mn SAURASHTRA SIGN VIRAMA
+A953 ; 9 # Mc REJANG VIRAMA
+10A3F ; 9 # Mn KHAROSHTHI VIRAMA
+
+# Total code points: 23
+
+# ================================================
+
+# Canonical_Combining_Class=10
+
+05B0 ; 10 # Mn HEBREW POINT SHEVA
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=11
+
+05B1 ; 11 # Mn HEBREW POINT HATAF SEGOL
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=12
+
+05B2 ; 12 # Mn HEBREW POINT HATAF PATAH
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=13
+
+05B3 ; 13 # Mn HEBREW POINT HATAF QAMATS
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=14
+
+05B4 ; 14 # Mn HEBREW POINT HIRIQ
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=15
+
+05B5 ; 15 # Mn HEBREW POINT TSERE
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=16
+
+05B6 ; 16 # Mn HEBREW POINT SEGOL
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=17
+
+05B7 ; 17 # Mn HEBREW POINT PATAH
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=18
+
+05B8 ; 18 # Mn HEBREW POINT QAMATS
+05C7 ; 18 # Mn HEBREW POINT QAMATS QATAN
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=19
+
+05B9..05BA ; 19 # Mn [2] HEBREW POINT HOLAM..HEBREW POINT HOLAM HASER FOR VAV
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=20
+
+05BB ; 20 # Mn HEBREW POINT QUBUTS
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=21
+
+05BC ; 21 # Mn HEBREW POINT DAGESH OR MAPIQ
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=22
+
+05BD ; 22 # Mn HEBREW POINT METEG
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=23
+
+05BF ; 23 # Mn HEBREW POINT RAFE
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=24
+
+05C1 ; 24 # Mn HEBREW POINT SHIN DOT
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=25
+
+05C2 ; 25 # Mn HEBREW POINT SIN DOT
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=26
+
+FB1E ; 26 # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=27
+
+064B ; 27 # Mn ARABIC FATHATAN
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=28
+
+064C ; 28 # Mn ARABIC DAMMATAN
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=29
+
+064D ; 29 # Mn ARABIC KASRATAN
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=30
+
+0618 ; 30 # Mn ARABIC SMALL FATHA
+064E ; 30 # Mn ARABIC FATHA
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=31
+
+0619 ; 31 # Mn ARABIC SMALL DAMMA
+064F ; 31 # Mn ARABIC DAMMA
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=32
+
+061A ; 32 # Mn ARABIC SMALL KASRA
+0650 ; 32 # Mn ARABIC KASRA
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=33
+
+0651 ; 33 # Mn ARABIC SHADDA
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=34
+
+0652 ; 34 # Mn ARABIC SUKUN
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=35
+
+0670 ; 35 # Mn ARABIC LETTER SUPERSCRIPT ALEF
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=36
+
+0711 ; 36 # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=84
+
+0C55 ; 84 # Mn TELUGU LENGTH MARK
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=91
+
+0C56 ; 91 # Mn TELUGU AI LENGTH MARK
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=103
+
+0E38..0E39 ; 103 # Mn [2] THAI CHARACTER SARA U..THAI CHARACTER SARA UU
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=107
+
+0E48..0E4B ; 107 # Mn [4] THAI CHARACTER MAI EK..THAI CHARACTER MAI CHATTAWA
+
+# Total code points: 4
+
+# ================================================
+
+# Canonical_Combining_Class=118
+
+0EB8..0EB9 ; 118 # Mn [2] LAO VOWEL SIGN U..LAO VOWEL SIGN UU
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=122
+
+0EC8..0ECB ; 122 # Mn [4] LAO TONE MAI EK..LAO TONE MAI CATAWA
+
+# Total code points: 4
+
+# ================================================
+
+# Canonical_Combining_Class=129
+
+0F71 ; 129 # Mn TIBETAN VOWEL SIGN AA
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=130
+
+0F72 ; 130 # Mn TIBETAN VOWEL SIGN I
+0F7A..0F7D ; 130 # Mn [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO
+0F80 ; 130 # Mn TIBETAN VOWEL SIGN REVERSED I
+
+# Total code points: 6
+
+# ================================================
+
+# Canonical_Combining_Class=132
+
+0F74 ; 132 # Mn TIBETAN VOWEL SIGN U
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=Attached_Below
+
+0321..0322 ; 202 # Mn [2] COMBINING PALATALIZED HOOK BELOW..COMBINING RETROFLEX HOOK BELOW
+0327..0328 ; 202 # Mn [2] COMBINING CEDILLA..COMBINING OGONEK
+1DD0 ; 202 # Mn COMBINING IS BELOW
+
+# Total code points: 5
+
+# ================================================
+
+# Canonical_Combining_Class=214
+
+1DCE ; 214 # Mn COMBINING OGONEK ABOVE
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=Attached_Above_Right
+
+031B ; 216 # Mn COMBINING HORN
+0F39 ; 216 # Mn TIBETAN MARK TSA -PHRU
+1D165..1D166 ; 216 # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D16E..1D172 ; 216 # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
+
+# Total code points: 9
+
+# ================================================
+
+# Canonical_Combining_Class=Below_Left
+
+302A ; 218 # Mn IDEOGRAPHIC LEVEL TONE MARK
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=Below
+
+0316..0319 ; 220 # Mn [4] COMBINING GRAVE ACCENT BELOW..COMBINING RIGHT TACK BELOW
+031C..0320 ; 220 # Mn [5] COMBINING LEFT HALF RING BELOW..COMBINING MINUS SIGN BELOW
+0323..0326 ; 220 # Mn [4] COMBINING DOT BELOW..COMBINING COMMA BELOW
+0329..0333 ; 220 # Mn [11] COMBINING VERTICAL LINE BELOW..COMBINING DOUBLE LOW LINE
+0339..033C ; 220 # Mn [4] COMBINING RIGHT HALF RING BELOW..COMBINING SEAGULL BELOW
+0347..0349 ; 220 # Mn [3] COMBINING EQUALS SIGN BELOW..COMBINING LEFT ANGLE BELOW
+034D..034E ; 220 # Mn [2] COMBINING LEFT RIGHT ARROW BELOW..COMBINING UPWARDS ARROW BELOW
+0353..0356 ; 220 # Mn [4] COMBINING X BELOW..COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW
+0359..035A ; 220 # Mn [2] COMBINING ASTERISK BELOW..COMBINING DOUBLE RING BELOW
+0591 ; 220 # Mn HEBREW ACCENT ETNAHTA
+0596 ; 220 # Mn HEBREW ACCENT TIPEHA
+059B ; 220 # Mn HEBREW ACCENT TEVIR
+05A2..05A7 ; 220 # Mn [6] HEBREW ACCENT ATNAH HAFUKH..HEBREW ACCENT DARGA
+05AA ; 220 # Mn HEBREW ACCENT YERAH BEN YOMO
+05C5 ; 220 # Mn HEBREW MARK LOWER DOT
+0655..0656 ; 220 # Mn [2] ARABIC HAMZA BELOW..ARABIC SUBSCRIPT ALEF
+065C ; 220 # Mn ARABIC VOWEL SIGN DOT BELOW
+06E3 ; 220 # Mn ARABIC SMALL LOW SEEN
+06EA ; 220 # Mn ARABIC EMPTY CENTRE LOW STOP
+06ED ; 220 # Mn ARABIC SMALL LOW MEEM
+0731 ; 220 # Mn SYRIAC PTHAHA BELOW
+0734 ; 220 # Mn SYRIAC ZQAPHA BELOW
+0737..0739 ; 220 # Mn [3] SYRIAC RBASA BELOW..SYRIAC DOTTED ZLAMA ANGULAR
+073B..073C ; 220 # Mn [2] SYRIAC HBASA BELOW..SYRIAC HBASA-ESASA DOTTED
+073E ; 220 # Mn SYRIAC ESASA BELOW
+0742 ; 220 # Mn SYRIAC RUKKAKHA
+0744 ; 220 # Mn SYRIAC TWO VERTICAL DOTS BELOW
+0746 ; 220 # Mn SYRIAC THREE DOTS BELOW
+0748 ; 220 # Mn SYRIAC OBLIQUE LINE BELOW
+07F2 ; 220 # Mn NKO COMBINING NASALIZATION MARK
+0952 ; 220 # Mn DEVANAGARI STRESS SIGN ANUDATTA
+0F18..0F19 ; 220 # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; 220 # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; 220 # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0FC6 ; 220 # Mn TIBETAN SYMBOL PADMA GDAN
+108D ; 220 # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+193B ; 220 # Mn LIMBU SIGN SA-I
+1A18 ; 220 # Mn BUGINESE VOWEL SIGN U
+1B6C ; 220 # Mn BALINESE MUSICAL SYMBOL COMBINING ENDEP
+1DC2 ; 220 # Mn COMBINING SNAKE BELOW
+1DCA ; 220 # Mn COMBINING LATIN SMALL LETTER R BELOW
+1DCF ; 220 # Mn COMBINING ZIGZAG BELOW
+1DFF ; 220 # Mn COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+20E8 ; 220 # Mn COMBINING TRIPLE UNDERDOT
+20EC..20EF ; 220 # Mn [4] COMBINING RIGHTWARDS HARPOON WITH BARB DOWNWARDS..COMBINING RIGHT ARROW BELOW
+A92B..A92D ; 220 # Mn [3] KAYAH LI TONE PLOPHU..KAYAH LI TONE CALYA PLOPHU
+101FD ; 220 # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+10A0D ; 220 # Mn KHAROSHTHI SIGN DOUBLE RING BELOW
+10A3A ; 220 # Mn KHAROSHTHI SIGN DOT BELOW
+1D17B..1D182 ; 220 # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D18A..1D18B ; 220 # Mn [2] MUSICAL SYMBOL COMBINING DOUBLE TONGUE..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+
+# Total code points: 104
+
+# ================================================
+
+# Canonical_Combining_Class=Below_Right
+
+059A ; 222 # Mn HEBREW ACCENT YETIV
+05AD ; 222 # Mn HEBREW ACCENT DEHI
+1939 ; 222 # Mn LIMBU SIGN MUKPHRENG
+302D ; 222 # Mn IDEOGRAPHIC ENTERING TONE MARK
+
+# Total code points: 4
+
+# ================================================
+
+# Canonical_Combining_Class=Left
+
+302E..302F ; 224 # Mn [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
+
+# Total code points: 2
+
+# ================================================
+
+# Canonical_Combining_Class=Right
+
+1D16D ; 226 # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
+
+# Total code points: 1
+
+# ================================================
+
+# Canonical_Combining_Class=Above_Left
+
+05AE ; 228 # Mn HEBREW ACCENT ZINOR
+18A9 ; 228 # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+302B ; 228 # Mn IDEOGRAPHIC RISING TONE MARK
+
+# Total code points: 3
+
+# ================================================
+
+# Canonical_Combining_Class=Above
+
+0300..0314 ; 230 # Mn [21] COMBINING GRAVE ACCENT..COMBINING REVERSED COMMA ABOVE
+033D..0344 ; 230 # Mn [8] COMBINING X ABOVE..COMBINING GREEK DIALYTIKA TONOS
+0346 ; 230 # Mn COMBINING BRIDGE ABOVE
+034A..034C ; 230 # Mn [3] COMBINING NOT TILDE ABOVE..COMBINING ALMOST EQUAL TO ABOVE
+0350..0352 ; 230 # Mn [3] COMBINING RIGHT ARROWHEAD ABOVE..COMBINING FERMATA
+0357 ; 230 # Mn COMBINING RIGHT HALF RING ABOVE
+035B ; 230 # Mn COMBINING ZIGZAG ABOVE
+0363..036F ; 230 # Mn [13] COMBINING LATIN SMALL LETTER A..COMBINING LATIN SMALL LETTER X
+0483..0487 ; 230 # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0592..0595 ; 230 # Mn [4] HEBREW ACCENT SEGOL..HEBREW ACCENT ZAQEF GADOL
+0597..0599 ; 230 # Mn [3] HEBREW ACCENT REVIA..HEBREW ACCENT PASHTA
+059C..05A1 ; 230 # Mn [6] HEBREW ACCENT GERESH..HEBREW ACCENT PAZER
+05A8..05A9 ; 230 # Mn [2] HEBREW ACCENT QADMA..HEBREW ACCENT TELISHA QETANA
+05AB..05AC ; 230 # Mn [2] HEBREW ACCENT OLE..HEBREW ACCENT ILUY
+05AF ; 230 # Mn HEBREW MARK MASORA CIRCLE
+05C4 ; 230 # Mn HEBREW MARK UPPER DOT
+0610..0617 ; 230 # Mn [8] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL HIGH ZAIN
+0653..0654 ; 230 # Mn [2] ARABIC MADDAH ABOVE..ARABIC HAMZA ABOVE
+0657..065B ; 230 # Mn [5] ARABIC INVERTED DAMMA..ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
+065D..065E ; 230 # Mn [2] ARABIC REVERSED DAMMA..ARABIC FATHA WITH TWO DOTS
+06D6..06DC ; 230 # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E2 ; 230 # Mn [4] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MEEM ISOLATED FORM
+06E4 ; 230 # Mn ARABIC SMALL HIGH MADDA
+06E7..06E8 ; 230 # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EB..06EC ; 230 # Mn [2] ARABIC EMPTY CENTRE HIGH STOP..ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE
+0730 ; 230 # Mn SYRIAC PTHAHA ABOVE
+0732..0733 ; 230 # Mn [2] SYRIAC PTHAHA DOTTED..SYRIAC ZQAPHA ABOVE
+0735..0736 ; 230 # Mn [2] SYRIAC ZQAPHA DOTTED..SYRIAC RBASA ABOVE
+073A ; 230 # Mn SYRIAC HBASA ABOVE
+073D ; 230 # Mn SYRIAC ESASA ABOVE
+073F..0741 ; 230 # Mn [3] SYRIAC RWAHA..SYRIAC QUSHSHAYA
+0743 ; 230 # Mn SYRIAC TWO VERTICAL DOTS ABOVE
+0745 ; 230 # Mn SYRIAC THREE DOTS ABOVE
+0747 ; 230 # Mn SYRIAC OBLIQUE LINE ABOVE
+0749..074A ; 230 # Mn [2] SYRIAC MUSIC..SYRIAC BARREKH
+07EB..07F1 ; 230 # Mn [7] NKO COMBINING SHORT HIGH TONE..NKO COMBINING LONG RISING TONE
+07F3 ; 230 # Mn NKO COMBINING DOUBLE DOT ABOVE
+0951 ; 230 # Mn DEVANAGARI STRESS SIGN UDATTA
+0953..0954 ; 230 # Mn [2] DEVANAGARI GRAVE ACCENT..DEVANAGARI ACUTE ACCENT
+0F82..0F83 ; 230 # Mn [2] TIBETAN SIGN NYI ZLA NAA DA..TIBETAN SIGN SNA LDAN
+0F86..0F87 ; 230 # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+135F ; 230 # Mn ETHIOPIC COMBINING GEMINATION MARK
+17DD ; 230 # Mn KHMER SIGN ATTHACAN
+193A ; 230 # Mn LIMBU SIGN KEMPHRENG
+1A17 ; 230 # Mn BUGINESE VOWEL SIGN I
+1B6B ; 230 # Mn BALINESE MUSICAL SYMBOL COMBINING TEGEH
+1B6D..1B73 ; 230 # Mn [7] BALINESE MUSICAL SYMBOL COMBINING KEMPUL..BALINESE MUSICAL SYMBOL COMBINING GONG
+1DC0..1DC1 ; 230 # Mn [2] COMBINING DOTTED GRAVE ACCENT..COMBINING DOTTED ACUTE ACCENT
+1DC3..1DC9 ; 230 # Mn [7] COMBINING SUSPENSION MARK..COMBINING ACUTE-GRAVE-ACUTE
+1DCB..1DCC ; 230 # Mn [2] COMBINING BREVE-MACRON..COMBINING MACRON-BREVE
+1DD1..1DE6 ; 230 # Mn [22] COMBINING UR ABOVE..COMBINING LATIN SMALL LETTER Z
+1DFE ; 230 # Mn COMBINING LEFT ARROWHEAD ABOVE
+20D0..20D1 ; 230 # Mn [2] COMBINING LEFT HARPOON ABOVE..COMBINING RIGHT HARPOON ABOVE
+20D4..20D7 ; 230 # Mn [4] COMBINING ANTICLOCKWISE ARROW ABOVE..COMBINING RIGHT ARROW ABOVE
+20DB..20DC ; 230 # Mn [2] COMBINING THREE DOTS ABOVE..COMBINING FOUR DOTS ABOVE
+20E1 ; 230 # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E7 ; 230 # Mn COMBINING ANNUITY SYMBOL
+20E9 ; 230 # Mn COMBINING WIDE BRIDGE ABOVE
+20F0 ; 230 # Mn COMBINING ASTERISK ABOVE
+2DE0..2DFF ; 230 # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+A66F ; 230 # Mn COMBINING CYRILLIC VZMET
+A67C..A67D ; 230 # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
+FE20..FE26 ; 230 # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
+10A0F ; 230 # Mn KHAROSHTHI SIGN VISARGA
+10A38 ; 230 # Mn KHAROSHTHI SIGN BAR ABOVE
+1D185..1D189 ; 230 # Mn [5] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING BEND
+1D1AA..1D1AD ; 230 # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; 230 # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+
+# Total code points: 252
+
+# ================================================
+
+# Canonical_Combining_Class=Above_Right
+
+0315 ; 232 # Mn COMBINING COMMA ABOVE RIGHT
+031A ; 232 # Mn COMBINING LEFT ANGLE ABOVE
+0358 ; 232 # Mn COMBINING DOT ABOVE RIGHT
+302C ; 232 # Mn IDEOGRAPHIC DEPARTING TONE MARK
+
+# Total code points: 4
+
+# ================================================
+
+# Canonical_Combining_Class=Double_Below
+
+035C ; 233 # Mn COMBINING DOUBLE BREVE BELOW
+035F ; 233 # Mn COMBINING DOUBLE MACRON BELOW
+0362 ; 233 # Mn COMBINING DOUBLE RIGHTWARDS ARROW BELOW
+
+# Total code points: 3
+
+# ================================================
+
+# Canonical_Combining_Class=Double_Above
+
+035D..035E ; 234 # Mn [2] COMBINING DOUBLE BREVE..COMBINING DOUBLE MACRON
+0360..0361 ; 234 # Mn [2] COMBINING DOUBLE TILDE..COMBINING DOUBLE INVERTED BREVE
+1DCD ; 234 # Mn COMBINING DOUBLE CIRCUMFLEX ABOVE
+
+# Total code points: 5
+
+# ================================================
+
+# Canonical_Combining_Class=Iota_Subscript
+
+0345 ; 240 # Mn COMBINING GREEK YPOGEGRAMMENI
+
+# Total code points: 1
+
+# EOF
diff --git a/third_party/harfbuzz/contrib/tables/DerivedGeneralCategory.txt b/third_party/harfbuzz/contrib/tables/DerivedGeneralCategory.txt
new file mode 100644
index 0000000..8423c70
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/DerivedGeneralCategory.txt
@@ -0,0 +1,3072 @@
+# DerivedGeneralCategory-5.1.0.txt
+# Date: 2008-03-20, 17:54:57 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2008 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+
+# ================================================
+
+# Property: General_Category
+
+# ================================================
+
+# General_Category=Unassigned
+
+0378..0379 ; Cn # [2] <reserved-0378>..<reserved-0379>
+037F..0383 ; Cn # [5] <reserved-037F>..<reserved-0383>
+038B ; Cn # <reserved-038B>
+038D ; Cn # <reserved-038D>
+03A2 ; Cn # <reserved-03A2>
+0524..0530 ; Cn # [13] <reserved-0524>..<reserved-0530>
+0557..0558 ; Cn # [2] <reserved-0557>..<reserved-0558>
+0560 ; Cn # <reserved-0560>
+0588 ; Cn # <reserved-0588>
+058B..0590 ; Cn # [6] <reserved-058B>..<reserved-0590>
+05C8..05CF ; Cn # [8] <reserved-05C8>..<reserved-05CF>
+05EB..05EF ; Cn # [5] <reserved-05EB>..<reserved-05EF>
+05F5..05FF ; Cn # [11] <reserved-05F5>..<reserved-05FF>
+0604..0605 ; Cn # [2] <reserved-0604>..<reserved-0605>
+061C..061D ; Cn # [2] <reserved-061C>..<reserved-061D>
+0620 ; Cn # <reserved-0620>
+065F ; Cn # <reserved-065F>
+070E ; Cn # <reserved-070E>
+074B..074C ; Cn # [2] <reserved-074B>..<reserved-074C>
+07B2..07BF ; Cn # [14] <reserved-07B2>..<reserved-07BF>
+07FB..0900 ; Cn # [262] <reserved-07FB>..<reserved-0900>
+093A..093B ; Cn # [2] <reserved-093A>..<reserved-093B>
+094E..094F ; Cn # [2] <reserved-094E>..<reserved-094F>
+0955..0957 ; Cn # [3] <reserved-0955>..<reserved-0957>
+0973..097A ; Cn # [8] <reserved-0973>..<reserved-097A>
+0980 ; Cn # <reserved-0980>
+0984 ; Cn # <reserved-0984>
+098D..098E ; Cn # [2] <reserved-098D>..<reserved-098E>
+0991..0992 ; Cn # [2] <reserved-0991>..<reserved-0992>
+09A9 ; Cn # <reserved-09A9>
+09B1 ; Cn # <reserved-09B1>
+09B3..09B5 ; Cn # [3] <reserved-09B3>..<reserved-09B5>
+09BA..09BB ; Cn # [2] <reserved-09BA>..<reserved-09BB>
+09C5..09C6 ; Cn # [2] <reserved-09C5>..<reserved-09C6>
+09C9..09CA ; Cn # [2] <reserved-09C9>..<reserved-09CA>
+09CF..09D6 ; Cn # [8] <reserved-09CF>..<reserved-09D6>
+09D8..09DB ; Cn # [4] <reserved-09D8>..<reserved-09DB>
+09DE ; Cn # <reserved-09DE>
+09E4..09E5 ; Cn # [2] <reserved-09E4>..<reserved-09E5>
+09FB..0A00 ; Cn # [6] <reserved-09FB>..<reserved-0A00>
+0A04 ; Cn # <reserved-0A04>
+0A0B..0A0E ; Cn # [4] <reserved-0A0B>..<reserved-0A0E>
+0A11..0A12 ; Cn # [2] <reserved-0A11>..<reserved-0A12>
+0A29 ; Cn # <reserved-0A29>
+0A31 ; Cn # <reserved-0A31>
+0A34 ; Cn # <reserved-0A34>
+0A37 ; Cn # <reserved-0A37>
+0A3A..0A3B ; Cn # [2] <reserved-0A3A>..<reserved-0A3B>
+0A3D ; Cn # <reserved-0A3D>
+0A43..0A46 ; Cn # [4] <reserved-0A43>..<reserved-0A46>
+0A49..0A4A ; Cn # [2] <reserved-0A49>..<reserved-0A4A>
+0A4E..0A50 ; Cn # [3] <reserved-0A4E>..<reserved-0A50>
+0A52..0A58 ; Cn # [7] <reserved-0A52>..<reserved-0A58>
+0A5D ; Cn # <reserved-0A5D>
+0A5F..0A65 ; Cn # [7] <reserved-0A5F>..<reserved-0A65>
+0A76..0A80 ; Cn # [11] <reserved-0A76>..<reserved-0A80>
+0A84 ; Cn # <reserved-0A84>
+0A8E ; Cn # <reserved-0A8E>
+0A92 ; Cn # <reserved-0A92>
+0AA9 ; Cn # <reserved-0AA9>
+0AB1 ; Cn # <reserved-0AB1>
+0AB4 ; Cn # <reserved-0AB4>
+0ABA..0ABB ; Cn # [2] <reserved-0ABA>..<reserved-0ABB>
+0AC6 ; Cn # <reserved-0AC6>
+0ACA ; Cn # <reserved-0ACA>
+0ACE..0ACF ; Cn # [2] <reserved-0ACE>..<reserved-0ACF>
+0AD1..0ADF ; Cn # [15] <reserved-0AD1>..<reserved-0ADF>
+0AE4..0AE5 ; Cn # [2] <reserved-0AE4>..<reserved-0AE5>
+0AF0 ; Cn # <reserved-0AF0>
+0AF2..0B00 ; Cn # [15] <reserved-0AF2>..<reserved-0B00>
+0B04 ; Cn # <reserved-0B04>
+0B0D..0B0E ; Cn # [2] <reserved-0B0D>..<reserved-0B0E>
+0B11..0B12 ; Cn # [2] <reserved-0B11>..<reserved-0B12>
+0B29 ; Cn # <reserved-0B29>
+0B31 ; Cn # <reserved-0B31>
+0B34 ; Cn # <reserved-0B34>
+0B3A..0B3B ; Cn # [2] <reserved-0B3A>..<reserved-0B3B>
+0B45..0B46 ; Cn # [2] <reserved-0B45>..<reserved-0B46>
+0B49..0B4A ; Cn # [2] <reserved-0B49>..<reserved-0B4A>
+0B4E..0B55 ; Cn # [8] <reserved-0B4E>..<reserved-0B55>
+0B58..0B5B ; Cn # [4] <reserved-0B58>..<reserved-0B5B>
+0B5E ; Cn # <reserved-0B5E>
+0B64..0B65 ; Cn # [2] <reserved-0B64>..<reserved-0B65>
+0B72..0B81 ; Cn # [16] <reserved-0B72>..<reserved-0B81>
+0B84 ; Cn # <reserved-0B84>
+0B8B..0B8D ; Cn # [3] <reserved-0B8B>..<reserved-0B8D>
+0B91 ; Cn # <reserved-0B91>
+0B96..0B98 ; Cn # [3] <reserved-0B96>..<reserved-0B98>
+0B9B ; Cn # <reserved-0B9B>
+0B9D ; Cn # <reserved-0B9D>
+0BA0..0BA2 ; Cn # [3] <reserved-0BA0>..<reserved-0BA2>
+0BA5..0BA7 ; Cn # [3] <reserved-0BA5>..<reserved-0BA7>
+0BAB..0BAD ; Cn # [3] <reserved-0BAB>..<reserved-0BAD>
+0BBA..0BBD ; Cn # [4] <reserved-0BBA>..<reserved-0BBD>
+0BC3..0BC5 ; Cn # [3] <reserved-0BC3>..<reserved-0BC5>
+0BC9 ; Cn # <reserved-0BC9>
+0BCE..0BCF ; Cn # [2] <reserved-0BCE>..<reserved-0BCF>
+0BD1..0BD6 ; Cn # [6] <reserved-0BD1>..<reserved-0BD6>
+0BD8..0BE5 ; Cn # [14] <reserved-0BD8>..<reserved-0BE5>
+0BFB..0C00 ; Cn # [6] <reserved-0BFB>..<reserved-0C00>
+0C04 ; Cn # <reserved-0C04>
+0C0D ; Cn # <reserved-0C0D>
+0C11 ; Cn # <reserved-0C11>
+0C29 ; Cn # <reserved-0C29>
+0C34 ; Cn # <reserved-0C34>
+0C3A..0C3C ; Cn # [3] <reserved-0C3A>..<reserved-0C3C>
+0C45 ; Cn # <reserved-0C45>
+0C49 ; Cn # <reserved-0C49>
+0C4E..0C54 ; Cn # [7] <reserved-0C4E>..<reserved-0C54>
+0C57 ; Cn # <reserved-0C57>
+0C5A..0C5F ; Cn # [6] <reserved-0C5A>..<reserved-0C5F>
+0C64..0C65 ; Cn # [2] <reserved-0C64>..<reserved-0C65>
+0C70..0C77 ; Cn # [8] <reserved-0C70>..<reserved-0C77>
+0C80..0C81 ; Cn # [2] <reserved-0C80>..<reserved-0C81>
+0C84 ; Cn # <reserved-0C84>
+0C8D ; Cn # <reserved-0C8D>
+0C91 ; Cn # <reserved-0C91>
+0CA9 ; Cn # <reserved-0CA9>
+0CB4 ; Cn # <reserved-0CB4>
+0CBA..0CBB ; Cn # [2] <reserved-0CBA>..<reserved-0CBB>
+0CC5 ; Cn # <reserved-0CC5>
+0CC9 ; Cn # <reserved-0CC9>
+0CCE..0CD4 ; Cn # [7] <reserved-0CCE>..<reserved-0CD4>
+0CD7..0CDD ; Cn # [7] <reserved-0CD7>..<reserved-0CDD>
+0CDF ; Cn # <reserved-0CDF>
+0CE4..0CE5 ; Cn # [2] <reserved-0CE4>..<reserved-0CE5>
+0CF0 ; Cn # <reserved-0CF0>
+0CF3..0D01 ; Cn # [15] <reserved-0CF3>..<reserved-0D01>
+0D04 ; Cn # <reserved-0D04>
+0D0D ; Cn # <reserved-0D0D>
+0D11 ; Cn # <reserved-0D11>
+0D29 ; Cn # <reserved-0D29>
+0D3A..0D3C ; Cn # [3] <reserved-0D3A>..<reserved-0D3C>
+0D45 ; Cn # <reserved-0D45>
+0D49 ; Cn # <reserved-0D49>
+0D4E..0D56 ; Cn # [9] <reserved-0D4E>..<reserved-0D56>
+0D58..0D5F ; Cn # [8] <reserved-0D58>..<reserved-0D5F>
+0D64..0D65 ; Cn # [2] <reserved-0D64>..<reserved-0D65>
+0D76..0D78 ; Cn # [3] <reserved-0D76>..<reserved-0D78>
+0D80..0D81 ; Cn # [2] <reserved-0D80>..<reserved-0D81>
+0D84 ; Cn # <reserved-0D84>
+0D97..0D99 ; Cn # [3] <reserved-0D97>..<reserved-0D99>
+0DB2 ; Cn # <reserved-0DB2>
+0DBC ; Cn # <reserved-0DBC>
+0DBE..0DBF ; Cn # [2] <reserved-0DBE>..<reserved-0DBF>
+0DC7..0DC9 ; Cn # [3] <reserved-0DC7>..<reserved-0DC9>
+0DCB..0DCE ; Cn # [4] <reserved-0DCB>..<reserved-0DCE>
+0DD5 ; Cn # <reserved-0DD5>
+0DD7 ; Cn # <reserved-0DD7>
+0DE0..0DF1 ; Cn # [18] <reserved-0DE0>..<reserved-0DF1>
+0DF5..0E00 ; Cn # [12] <reserved-0DF5>..<reserved-0E00>
+0E3B..0E3E ; Cn # [4] <reserved-0E3B>..<reserved-0E3E>
+0E5C..0E80 ; Cn # [37] <reserved-0E5C>..<reserved-0E80>
+0E83 ; Cn # <reserved-0E83>
+0E85..0E86 ; Cn # [2] <reserved-0E85>..<reserved-0E86>
+0E89 ; Cn # <reserved-0E89>
+0E8B..0E8C ; Cn # [2] <reserved-0E8B>..<reserved-0E8C>
+0E8E..0E93 ; Cn # [6] <reserved-0E8E>..<reserved-0E93>
+0E98 ; Cn # <reserved-0E98>
+0EA0 ; Cn # <reserved-0EA0>
+0EA4 ; Cn # <reserved-0EA4>
+0EA6 ; Cn # <reserved-0EA6>
+0EA8..0EA9 ; Cn # [2] <reserved-0EA8>..<reserved-0EA9>
+0EAC ; Cn # <reserved-0EAC>
+0EBA ; Cn # <reserved-0EBA>
+0EBE..0EBF ; Cn # [2] <reserved-0EBE>..<reserved-0EBF>
+0EC5 ; Cn # <reserved-0EC5>
+0EC7 ; Cn # <reserved-0EC7>
+0ECE..0ECF ; Cn # [2] <reserved-0ECE>..<reserved-0ECF>
+0EDA..0EDB ; Cn # [2] <reserved-0EDA>..<reserved-0EDB>
+0EDE..0EFF ; Cn # [34] <reserved-0EDE>..<reserved-0EFF>
+0F48 ; Cn # <reserved-0F48>
+0F6D..0F70 ; Cn # [4] <reserved-0F6D>..<reserved-0F70>
+0F8C..0F8F ; Cn # [4] <reserved-0F8C>..<reserved-0F8F>
+0F98 ; Cn # <reserved-0F98>
+0FBD ; Cn # <reserved-0FBD>
+0FCD ; Cn # <reserved-0FCD>
+0FD5..0FFF ; Cn # [43] <reserved-0FD5>..<reserved-0FFF>
+109A..109D ; Cn # [4] <reserved-109A>..<reserved-109D>
+10C6..10CF ; Cn # [10] <reserved-10C6>..<reserved-10CF>
+10FD..10FF ; Cn # [3] <reserved-10FD>..<reserved-10FF>
+115A..115E ; Cn # [5] <reserved-115A>..<reserved-115E>
+11A3..11A7 ; Cn # [5] <reserved-11A3>..<reserved-11A7>
+11FA..11FF ; Cn # [6] <reserved-11FA>..<reserved-11FF>
+1249 ; Cn # <reserved-1249>
+124E..124F ; Cn # [2] <reserved-124E>..<reserved-124F>
+1257 ; Cn # <reserved-1257>
+1259 ; Cn # <reserved-1259>
+125E..125F ; Cn # [2] <reserved-125E>..<reserved-125F>
+1289 ; Cn # <reserved-1289>
+128E..128F ; Cn # [2] <reserved-128E>..<reserved-128F>
+12B1 ; Cn # <reserved-12B1>
+12B6..12B7 ; Cn # [2] <reserved-12B6>..<reserved-12B7>
+12BF ; Cn # <reserved-12BF>
+12C1 ; Cn # <reserved-12C1>
+12C6..12C7 ; Cn # [2] <reserved-12C6>..<reserved-12C7>
+12D7 ; Cn # <reserved-12D7>
+1311 ; Cn # <reserved-1311>
+1316..1317 ; Cn # [2] <reserved-1316>..<reserved-1317>
+135B..135E ; Cn # [4] <reserved-135B>..<reserved-135E>
+137D..137F ; Cn # [3] <reserved-137D>..<reserved-137F>
+139A..139F ; Cn # [6] <reserved-139A>..<reserved-139F>
+13F5..1400 ; Cn # [12] <reserved-13F5>..<reserved-1400>
+1677..167F ; Cn # [9] <reserved-1677>..<reserved-167F>
+169D..169F ; Cn # [3] <reserved-169D>..<reserved-169F>
+16F1..16FF ; Cn # [15] <reserved-16F1>..<reserved-16FF>
+170D ; Cn # <reserved-170D>
+1715..171F ; Cn # [11] <reserved-1715>..<reserved-171F>
+1737..173F ; Cn # [9] <reserved-1737>..<reserved-173F>
+1754..175F ; Cn # [12] <reserved-1754>..<reserved-175F>
+176D ; Cn # <reserved-176D>
+1771 ; Cn # <reserved-1771>
+1774..177F ; Cn # [12] <reserved-1774>..<reserved-177F>
+17DE..17DF ; Cn # [2] <reserved-17DE>..<reserved-17DF>
+17EA..17EF ; Cn # [6] <reserved-17EA>..<reserved-17EF>
+17FA..17FF ; Cn # [6] <reserved-17FA>..<reserved-17FF>
+180F ; Cn # <reserved-180F>
+181A..181F ; Cn # [6] <reserved-181A>..<reserved-181F>
+1878..187F ; Cn # [8] <reserved-1878>..<reserved-187F>
+18AB..18FF ; Cn # [85] <reserved-18AB>..<reserved-18FF>
+191D..191F ; Cn # [3] <reserved-191D>..<reserved-191F>
+192C..192F ; Cn # [4] <reserved-192C>..<reserved-192F>
+193C..193F ; Cn # [4] <reserved-193C>..<reserved-193F>
+1941..1943 ; Cn # [3] <reserved-1941>..<reserved-1943>
+196E..196F ; Cn # [2] <reserved-196E>..<reserved-196F>
+1975..197F ; Cn # [11] <reserved-1975>..<reserved-197F>
+19AA..19AF ; Cn # [6] <reserved-19AA>..<reserved-19AF>
+19CA..19CF ; Cn # [6] <reserved-19CA>..<reserved-19CF>
+19DA..19DD ; Cn # [4] <reserved-19DA>..<reserved-19DD>
+1A1C..1A1D ; Cn # [2] <reserved-1A1C>..<reserved-1A1D>
+1A20..1AFF ; Cn # [224] <reserved-1A20>..<reserved-1AFF>
+1B4C..1B4F ; Cn # [4] <reserved-1B4C>..<reserved-1B4F>
+1B7D..1B7F ; Cn # [3] <reserved-1B7D>..<reserved-1B7F>
+1BAB..1BAD ; Cn # [3] <reserved-1BAB>..<reserved-1BAD>
+1BBA..1BFF ; Cn # [70] <reserved-1BBA>..<reserved-1BFF>
+1C38..1C3A ; Cn # [3] <reserved-1C38>..<reserved-1C3A>
+1C4A..1C4C ; Cn # [3] <reserved-1C4A>..<reserved-1C4C>
+1C80..1CFF ; Cn # [128] <reserved-1C80>..<reserved-1CFF>
+1DE7..1DFD ; Cn # [23] <reserved-1DE7>..<reserved-1DFD>
+1F16..1F17 ; Cn # [2] <reserved-1F16>..<reserved-1F17>
+1F1E..1F1F ; Cn # [2] <reserved-1F1E>..<reserved-1F1F>
+1F46..1F47 ; Cn # [2] <reserved-1F46>..<reserved-1F47>
+1F4E..1F4F ; Cn # [2] <reserved-1F4E>..<reserved-1F4F>
+1F58 ; Cn # <reserved-1F58>
+1F5A ; Cn # <reserved-1F5A>
+1F5C ; Cn # <reserved-1F5C>
+1F5E ; Cn # <reserved-1F5E>
+1F7E..1F7F ; Cn # [2] <reserved-1F7E>..<reserved-1F7F>
+1FB5 ; Cn # <reserved-1FB5>
+1FC5 ; Cn # <reserved-1FC5>
+1FD4..1FD5 ; Cn # [2] <reserved-1FD4>..<reserved-1FD5>
+1FDC ; Cn # <reserved-1FDC>
+1FF0..1FF1 ; Cn # [2] <reserved-1FF0>..<reserved-1FF1>
+1FF5 ; Cn # <reserved-1FF5>
+1FFF ; Cn # <reserved-1FFF>
+2065..2069 ; Cn # [5] <reserved-2065>..<reserved-2069>
+2072..2073 ; Cn # [2] <reserved-2072>..<reserved-2073>
+208F ; Cn # <reserved-208F>
+2095..209F ; Cn # [11] <reserved-2095>..<reserved-209F>
+20B6..20CF ; Cn # [26] <reserved-20B6>..<reserved-20CF>
+20F1..20FF ; Cn # [15] <reserved-20F1>..<reserved-20FF>
+2150..2152 ; Cn # [3] <reserved-2150>..<reserved-2152>
+2189..218F ; Cn # [7] <reserved-2189>..<reserved-218F>
+23E8..23FF ; Cn # [24] <reserved-23E8>..<reserved-23FF>
+2427..243F ; Cn # [25] <reserved-2427>..<reserved-243F>
+244B..245F ; Cn # [21] <reserved-244B>..<reserved-245F>
+269E..269F ; Cn # [2] <reserved-269E>..<reserved-269F>
+26BD..26BF ; Cn # [3] <reserved-26BD>..<reserved-26BF>
+26C4..2700 ; Cn # [61] <reserved-26C4>..<reserved-2700>
+2705 ; Cn # <reserved-2705>
+270A..270B ; Cn # [2] <reserved-270A>..<reserved-270B>
+2728 ; Cn # <reserved-2728>
+274C ; Cn # <reserved-274C>
+274E ; Cn # <reserved-274E>
+2753..2755 ; Cn # [3] <reserved-2753>..<reserved-2755>
+2757 ; Cn # <reserved-2757>
+275F..2760 ; Cn # [2] <reserved-275F>..<reserved-2760>
+2795..2797 ; Cn # [3] <reserved-2795>..<reserved-2797>
+27B0 ; Cn # <reserved-27B0>
+27BF ; Cn # <reserved-27BF>
+27CB ; Cn # <reserved-27CB>
+27CD..27CF ; Cn # [3] <reserved-27CD>..<reserved-27CF>
+2B4D..2B4F ; Cn # [3] <reserved-2B4D>..<reserved-2B4F>
+2B55..2BFF ; Cn # [171] <reserved-2B55>..<reserved-2BFF>
+2C2F ; Cn # <reserved-2C2F>
+2C5F ; Cn # <reserved-2C5F>
+2C70 ; Cn # <reserved-2C70>
+2C7E..2C7F ; Cn # [2] <reserved-2C7E>..<reserved-2C7F>
+2CEB..2CF8 ; Cn # [14] <reserved-2CEB>..<reserved-2CF8>
+2D26..2D2F ; Cn # [10] <reserved-2D26>..<reserved-2D2F>
+2D66..2D6E ; Cn # [9] <reserved-2D66>..<reserved-2D6E>
+2D70..2D7F ; Cn # [16] <reserved-2D70>..<reserved-2D7F>
+2D97..2D9F ; Cn # [9] <reserved-2D97>..<reserved-2D9F>
+2DA7 ; Cn # <reserved-2DA7>
+2DAF ; Cn # <reserved-2DAF>
+2DB7 ; Cn # <reserved-2DB7>
+2DBF ; Cn # <reserved-2DBF>
+2DC7 ; Cn # <reserved-2DC7>
+2DCF ; Cn # <reserved-2DCF>
+2DD7 ; Cn # <reserved-2DD7>
+2DDF ; Cn # <reserved-2DDF>
+2E31..2E7F ; Cn # [79] <reserved-2E31>..<reserved-2E7F>
+2E9A ; Cn # <reserved-2E9A>
+2EF4..2EFF ; Cn # [12] <reserved-2EF4>..<reserved-2EFF>
+2FD6..2FEF ; Cn # [26] <reserved-2FD6>..<reserved-2FEF>
+2FFC..2FFF ; Cn # [4] <reserved-2FFC>..<reserved-2FFF>
+3040 ; Cn # <reserved-3040>
+3097..3098 ; Cn # [2] <reserved-3097>..<reserved-3098>
+3100..3104 ; Cn # [5] <reserved-3100>..<reserved-3104>
+312E..3130 ; Cn # [3] <reserved-312E>..<reserved-3130>
+318F ; Cn # <reserved-318F>
+31B8..31BF ; Cn # [8] <reserved-31B8>..<reserved-31BF>
+31E4..31EF ; Cn # [12] <reserved-31E4>..<reserved-31EF>
+321F ; Cn # <reserved-321F>
+3244..324F ; Cn # [12] <reserved-3244>..<reserved-324F>
+32FF ; Cn # <reserved-32FF>
+4DB6..4DBF ; Cn # [10] <reserved-4DB6>..<reserved-4DBF>
+9FC4..9FFF ; Cn # [60] <reserved-9FC4>..<reserved-9FFF>
+A48D..A48F ; Cn # [3] <reserved-A48D>..<reserved-A48F>
+A4C7..A4FF ; Cn # [57] <reserved-A4C7>..<reserved-A4FF>
+A62C..A63F ; Cn # [20] <reserved-A62C>..<reserved-A63F>
+A660..A661 ; Cn # [2] <reserved-A660>..<reserved-A661>
+A674..A67B ; Cn # [8] <reserved-A674>..<reserved-A67B>
+A698..A6FF ; Cn # [104] <reserved-A698>..<reserved-A6FF>
+A78D..A7FA ; Cn # [110] <reserved-A78D>..<reserved-A7FA>
+A82C..A83F ; Cn # [20] <reserved-A82C>..<reserved-A83F>
+A878..A87F ; Cn # [8] <reserved-A878>..<reserved-A87F>
+A8C5..A8CD ; Cn # [9] <reserved-A8C5>..<reserved-A8CD>
+A8DA..A8FF ; Cn # [38] <reserved-A8DA>..<reserved-A8FF>
+A954..A95E ; Cn # [11] <reserved-A954>..<reserved-A95E>
+A960..A9FF ; Cn # [160] <reserved-A960>..<reserved-A9FF>
+AA37..AA3F ; Cn # [9] <reserved-AA37>..<reserved-AA3F>
+AA4E..AA4F ; Cn # [2] <reserved-AA4E>..<reserved-AA4F>
+AA5A..AA5B ; Cn # [2] <reserved-AA5A>..<reserved-AA5B>
+AA60..ABFF ; Cn # [416] <reserved-AA60>..<reserved-ABFF>
+D7A4..D7FF ; Cn # [92] <reserved-D7A4>..<reserved-D7FF>
+FA2E..FA2F ; Cn # [2] <reserved-FA2E>..<reserved-FA2F>
+FA6B..FA6F ; Cn # [5] <reserved-FA6B>..<reserved-FA6F>
+FADA..FAFF ; Cn # [38] <reserved-FADA>..<reserved-FAFF>
+FB07..FB12 ; Cn # [12] <reserved-FB07>..<reserved-FB12>
+FB18..FB1C ; Cn # [5] <reserved-FB18>..<reserved-FB1C>
+FB37 ; Cn # <reserved-FB37>
+FB3D ; Cn # <reserved-FB3D>
+FB3F ; Cn # <reserved-FB3F>
+FB42 ; Cn # <reserved-FB42>
+FB45 ; Cn # <reserved-FB45>
+FBB2..FBD2 ; Cn # [33] <reserved-FBB2>..<reserved-FBD2>
+FD40..FD4F ; Cn # [16] <reserved-FD40>..<reserved-FD4F>
+FD90..FD91 ; Cn # [2] <reserved-FD90>..<reserved-FD91>
+FDC8..FDEF ; Cn # [40] <reserved-FDC8>..<noncharacter-FDEF>
+FDFE..FDFF ; Cn # [2] <reserved-FDFE>..<reserved-FDFF>
+FE1A..FE1F ; Cn # [6] <reserved-FE1A>..<reserved-FE1F>
+FE27..FE2F ; Cn # [9] <reserved-FE27>..<reserved-FE2F>
+FE53 ; Cn # <reserved-FE53>
+FE67 ; Cn # <reserved-FE67>
+FE6C..FE6F ; Cn # [4] <reserved-FE6C>..<reserved-FE6F>
+FE75 ; Cn # <reserved-FE75>
+FEFD..FEFE ; Cn # [2] <reserved-FEFD>..<reserved-FEFE>
+FF00 ; Cn # <reserved-FF00>
+FFBF..FFC1 ; Cn # [3] <reserved-FFBF>..<reserved-FFC1>
+FFC8..FFC9 ; Cn # [2] <reserved-FFC8>..<reserved-FFC9>
+FFD0..FFD1 ; Cn # [2] <reserved-FFD0>..<reserved-FFD1>
+FFD8..FFD9 ; Cn # [2] <reserved-FFD8>..<reserved-FFD9>
+FFDD..FFDF ; Cn # [3] <reserved-FFDD>..<reserved-FFDF>
+FFE7 ; Cn # <reserved-FFE7>
+FFEF..FFF8 ; Cn # [10] <reserved-FFEF>..<reserved-FFF8>
+FFFE..FFFF ; Cn # [2] <noncharacter-FFFE>..<noncharacter-FFFF>
+1000C ; Cn # <reserved-1000C>
+10027 ; Cn # <reserved-10027>
+1003B ; Cn # <reserved-1003B>
+1003E ; Cn # <reserved-1003E>
+1004E..1004F ; Cn # [2] <reserved-1004E>..<reserved-1004F>
+1005E..1007F ; Cn # [34] <reserved-1005E>..<reserved-1007F>
+100FB..100FF ; Cn # [5] <reserved-100FB>..<reserved-100FF>
+10103..10106 ; Cn # [4] <reserved-10103>..<reserved-10106>
+10134..10136 ; Cn # [3] <reserved-10134>..<reserved-10136>
+1018B..1018F ; Cn # [5] <reserved-1018B>..<reserved-1018F>
+1019C..101CF ; Cn # [52] <reserved-1019C>..<reserved-101CF>
+101FE..1027F ; Cn # [130] <reserved-101FE>..<reserved-1027F>
+1029D..1029F ; Cn # [3] <reserved-1029D>..<reserved-1029F>
+102D1..102FF ; Cn # [47] <reserved-102D1>..<reserved-102FF>
+1031F ; Cn # <reserved-1031F>
+10324..1032F ; Cn # [12] <reserved-10324>..<reserved-1032F>
+1034B..1037F ; Cn # [53] <reserved-1034B>..<reserved-1037F>
+1039E ; Cn # <reserved-1039E>
+103C4..103C7 ; Cn # [4] <reserved-103C4>..<reserved-103C7>
+103D6..103FF ; Cn # [42] <reserved-103D6>..<reserved-103FF>
+1049E..1049F ; Cn # [2] <reserved-1049E>..<reserved-1049F>
+104AA..107FF ; Cn # [854] <reserved-104AA>..<reserved-107FF>
+10806..10807 ; Cn # [2] <reserved-10806>..<reserved-10807>
+10809 ; Cn # <reserved-10809>
+10836 ; Cn # <reserved-10836>
+10839..1083B ; Cn # [3] <reserved-10839>..<reserved-1083B>
+1083D..1083E ; Cn # [2] <reserved-1083D>..<reserved-1083E>
+10840..108FF ; Cn # [192] <reserved-10840>..<reserved-108FF>
+1091A..1091E ; Cn # [5] <reserved-1091A>..<reserved-1091E>
+1093A..1093E ; Cn # [5] <reserved-1093A>..<reserved-1093E>
+10940..109FF ; Cn # [192] <reserved-10940>..<reserved-109FF>
+10A04 ; Cn # <reserved-10A04>
+10A07..10A0B ; Cn # [5] <reserved-10A07>..<reserved-10A0B>
+10A14 ; Cn # <reserved-10A14>
+10A18 ; Cn # <reserved-10A18>
+10A34..10A37 ; Cn # [4] <reserved-10A34>..<reserved-10A37>
+10A3B..10A3E ; Cn # [4] <reserved-10A3B>..<reserved-10A3E>
+10A48..10A4F ; Cn # [8] <reserved-10A48>..<reserved-10A4F>
+10A59..11FFF ; Cn # [5543] <reserved-10A59>..<reserved-11FFF>
+1236F..123FF ; Cn # [145] <reserved-1236F>..<reserved-123FF>
+12463..1246F ; Cn # [13] <reserved-12463>..<reserved-1246F>
+12474..1CFFF ; Cn # [43916] <reserved-12474>..<reserved-1CFFF>
+1D0F6..1D0FF ; Cn # [10] <reserved-1D0F6>..<reserved-1D0FF>
+1D127..1D128 ; Cn # [2] <reserved-1D127>..<reserved-1D128>
+1D1DE..1D1FF ; Cn # [34] <reserved-1D1DE>..<reserved-1D1FF>
+1D246..1D2FF ; Cn # [186] <reserved-1D246>..<reserved-1D2FF>
+1D357..1D35F ; Cn # [9] <reserved-1D357>..<reserved-1D35F>
+1D372..1D3FF ; Cn # [142] <reserved-1D372>..<reserved-1D3FF>
+1D455 ; Cn # <reserved-1D455>
+1D49D ; Cn # <reserved-1D49D>
+1D4A0..1D4A1 ; Cn # [2] <reserved-1D4A0>..<reserved-1D4A1>
+1D4A3..1D4A4 ; Cn # [2] <reserved-1D4A3>..<reserved-1D4A4>
+1D4A7..1D4A8 ; Cn # [2] <reserved-1D4A7>..<reserved-1D4A8>
+1D4AD ; Cn # <reserved-1D4AD>
+1D4BA ; Cn # <reserved-1D4BA>
+1D4BC ; Cn # <reserved-1D4BC>
+1D4C4 ; Cn # <reserved-1D4C4>
+1D506 ; Cn # <reserved-1D506>
+1D50B..1D50C ; Cn # [2] <reserved-1D50B>..<reserved-1D50C>
+1D515 ; Cn # <reserved-1D515>
+1D51D ; Cn # <reserved-1D51D>
+1D53A ; Cn # <reserved-1D53A>
+1D53F ; Cn # <reserved-1D53F>
+1D545 ; Cn # <reserved-1D545>
+1D547..1D549 ; Cn # [3] <reserved-1D547>..<reserved-1D549>
+1D551 ; Cn # <reserved-1D551>
+1D6A6..1D6A7 ; Cn # [2] <reserved-1D6A6>..<reserved-1D6A7>
+1D7CC..1D7CD ; Cn # [2] <reserved-1D7CC>..<reserved-1D7CD>
+1D800..1EFFF ; Cn # [6144] <reserved-1D800>..<reserved-1EFFF>
+1F02C..1F02F ; Cn # [4] <reserved-1F02C>..<reserved-1F02F>
+1F094..1FFFF ; Cn # [3948] <reserved-1F094>..<noncharacter-1FFFF>
+2A6D7..2F7FF ; Cn # [20777] <reserved-2A6D7>..<reserved-2F7FF>
+2FA1E..E0000 ; Cn # [722403] <reserved-2FA1E>..<reserved-E0000>
+E0002..E001F ; Cn # [30] <reserved-E0002>..<reserved-E001F>
+E0080..E00FF ; Cn # [128] <reserved-E0080>..<reserved-E00FF>
+E01F0..EFFFF ; Cn # [65040] <reserved-E01F0>..<noncharacter-EFFFF>
+FFFFE..FFFFF ; Cn # [2] <noncharacter-FFFFE>..<noncharacter-FFFFF>
+10FFFE..10FFFF; Cn # [2] <noncharacter-10FFFE>..<noncharacter-10FFFF>
+
+# Total code points: 873883
+
+# ================================================
+
+# General_Category=Uppercase_Letter
+
+0041..005A ; Lu # [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+00C0..00D6 ; Lu # [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00DE ; Lu # [7] LATIN CAPITAL LETTER O WITH STROKE..LATIN CAPITAL LETTER THORN
+0100 ; Lu # LATIN CAPITAL LETTER A WITH MACRON
+0102 ; Lu # LATIN CAPITAL LETTER A WITH BREVE
+0104 ; Lu # LATIN CAPITAL LETTER A WITH OGONEK
+0106 ; Lu # LATIN CAPITAL LETTER C WITH ACUTE
+0108 ; Lu # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A ; Lu # LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C ; Lu # LATIN CAPITAL LETTER C WITH CARON
+010E ; Lu # LATIN CAPITAL LETTER D WITH CARON
+0110 ; Lu # LATIN CAPITAL LETTER D WITH STROKE
+0112 ; Lu # LATIN CAPITAL LETTER E WITH MACRON
+0114 ; Lu # LATIN CAPITAL LETTER E WITH BREVE
+0116 ; Lu # LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118 ; Lu # LATIN CAPITAL LETTER E WITH OGONEK
+011A ; Lu # LATIN CAPITAL LETTER E WITH CARON
+011C ; Lu # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E ; Lu # LATIN CAPITAL LETTER G WITH BREVE
+0120 ; Lu # LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122 ; Lu # LATIN CAPITAL LETTER G WITH CEDILLA
+0124 ; Lu # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126 ; Lu # LATIN CAPITAL LETTER H WITH STROKE
+0128 ; Lu # LATIN CAPITAL LETTER I WITH TILDE
+012A ; Lu # LATIN CAPITAL LETTER I WITH MACRON
+012C ; Lu # LATIN CAPITAL LETTER I WITH BREVE
+012E ; Lu # LATIN CAPITAL LETTER I WITH OGONEK
+0130 ; Lu # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132 ; Lu # LATIN CAPITAL LIGATURE IJ
+0134 ; Lu # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136 ; Lu # LATIN CAPITAL LETTER K WITH CEDILLA
+0139 ; Lu # LATIN CAPITAL LETTER L WITH ACUTE
+013B ; Lu # LATIN CAPITAL LETTER L WITH CEDILLA
+013D ; Lu # LATIN CAPITAL LETTER L WITH CARON
+013F ; Lu # LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141 ; Lu # LATIN CAPITAL LETTER L WITH STROKE
+0143 ; Lu # LATIN CAPITAL LETTER N WITH ACUTE
+0145 ; Lu # LATIN CAPITAL LETTER N WITH CEDILLA
+0147 ; Lu # LATIN CAPITAL LETTER N WITH CARON
+014A ; Lu # LATIN CAPITAL LETTER ENG
+014C ; Lu # LATIN CAPITAL LETTER O WITH MACRON
+014E ; Lu # LATIN CAPITAL LETTER O WITH BREVE
+0150 ; Lu # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152 ; Lu # LATIN CAPITAL LIGATURE OE
+0154 ; Lu # LATIN CAPITAL LETTER R WITH ACUTE
+0156 ; Lu # LATIN CAPITAL LETTER R WITH CEDILLA
+0158 ; Lu # LATIN CAPITAL LETTER R WITH CARON
+015A ; Lu # LATIN CAPITAL LETTER S WITH ACUTE
+015C ; Lu # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E ; Lu # LATIN CAPITAL LETTER S WITH CEDILLA
+0160 ; Lu # LATIN CAPITAL LETTER S WITH CARON
+0162 ; Lu # LATIN CAPITAL LETTER T WITH CEDILLA
+0164 ; Lu # LATIN CAPITAL LETTER T WITH CARON
+0166 ; Lu # LATIN CAPITAL LETTER T WITH STROKE
+0168 ; Lu # LATIN CAPITAL LETTER U WITH TILDE
+016A ; Lu # LATIN CAPITAL LETTER U WITH MACRON
+016C ; Lu # LATIN CAPITAL LETTER U WITH BREVE
+016E ; Lu # LATIN CAPITAL LETTER U WITH RING ABOVE
+0170 ; Lu # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172 ; Lu # LATIN CAPITAL LETTER U WITH OGONEK
+0174 ; Lu # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176 ; Lu # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178..0179 ; Lu # [2] LATIN CAPITAL LETTER Y WITH DIAERESIS..LATIN CAPITAL LETTER Z WITH ACUTE
+017B ; Lu # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D ; Lu # LATIN CAPITAL LETTER Z WITH CARON
+0181..0182 ; Lu # [2] LATIN CAPITAL LETTER B WITH HOOK..LATIN CAPITAL LETTER B WITH TOPBAR
+0184 ; Lu # LATIN CAPITAL LETTER TONE SIX
+0186..0187 ; Lu # [2] LATIN CAPITAL LETTER OPEN O..LATIN CAPITAL LETTER C WITH HOOK
+0189..018B ; Lu # [3] LATIN CAPITAL LETTER AFRICAN D..LATIN CAPITAL LETTER D WITH TOPBAR
+018E..0191 ; Lu # [4] LATIN CAPITAL LETTER REVERSED E..LATIN CAPITAL LETTER F WITH HOOK
+0193..0194 ; Lu # [2] LATIN CAPITAL LETTER G WITH HOOK..LATIN CAPITAL LETTER GAMMA
+0196..0198 ; Lu # [3] LATIN CAPITAL LETTER IOTA..LATIN CAPITAL LETTER K WITH HOOK
+019C..019D ; Lu # [2] LATIN CAPITAL LETTER TURNED M..LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F..01A0 ; Lu # [2] LATIN CAPITAL LETTER O WITH MIDDLE TILDE..LATIN CAPITAL LETTER O WITH HORN
+01A2 ; Lu # LATIN CAPITAL LETTER OI
+01A4 ; Lu # LATIN CAPITAL LETTER P WITH HOOK
+01A6..01A7 ; Lu # [2] LATIN LETTER YR..LATIN CAPITAL LETTER TONE TWO
+01A9 ; Lu # LATIN CAPITAL LETTER ESH
+01AC ; Lu # LATIN CAPITAL LETTER T WITH HOOK
+01AE..01AF ; Lu # [2] LATIN CAPITAL LETTER T WITH RETROFLEX HOOK..LATIN CAPITAL LETTER U WITH HORN
+01B1..01B3 ; Lu # [3] LATIN CAPITAL LETTER UPSILON..LATIN CAPITAL LETTER Y WITH HOOK
+01B5 ; Lu # LATIN CAPITAL LETTER Z WITH STROKE
+01B7..01B8 ; Lu # [2] LATIN CAPITAL LETTER EZH..LATIN CAPITAL LETTER EZH REVERSED
+01BC ; Lu # LATIN CAPITAL LETTER TONE FIVE
+01C4 ; Lu # LATIN CAPITAL LETTER DZ WITH CARON
+01C7 ; Lu # LATIN CAPITAL LETTER LJ
+01CA ; Lu # LATIN CAPITAL LETTER NJ
+01CD ; Lu # LATIN CAPITAL LETTER A WITH CARON
+01CF ; Lu # LATIN CAPITAL LETTER I WITH CARON
+01D1 ; Lu # LATIN CAPITAL LETTER O WITH CARON
+01D3 ; Lu # LATIN CAPITAL LETTER U WITH CARON
+01D5 ; Lu # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7 ; Lu # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9 ; Lu # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB ; Lu # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE ; Lu # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0 ; Lu # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2 ; Lu # LATIN CAPITAL LETTER AE WITH MACRON
+01E4 ; Lu # LATIN CAPITAL LETTER G WITH STROKE
+01E6 ; Lu # LATIN CAPITAL LETTER G WITH CARON
+01E8 ; Lu # LATIN CAPITAL LETTER K WITH CARON
+01EA ; Lu # LATIN CAPITAL LETTER O WITH OGONEK
+01EC ; Lu # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE ; Lu # LATIN CAPITAL LETTER EZH WITH CARON
+01F1 ; Lu # LATIN CAPITAL LETTER DZ
+01F4 ; Lu # LATIN CAPITAL LETTER G WITH ACUTE
+01F6..01F8 ; Lu # [3] LATIN CAPITAL LETTER HWAIR..LATIN CAPITAL LETTER N WITH GRAVE
+01FA ; Lu # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC ; Lu # LATIN CAPITAL LETTER AE WITH ACUTE
+01FE ; Lu # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200 ; Lu # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202 ; Lu # LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204 ; Lu # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206 ; Lu # LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208 ; Lu # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A ; Lu # LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C ; Lu # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E ; Lu # LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210 ; Lu # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212 ; Lu # LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214 ; Lu # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216 ; Lu # LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218 ; Lu # LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A ; Lu # LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C ; Lu # LATIN CAPITAL LETTER YOGH
+021E ; Lu # LATIN CAPITAL LETTER H WITH CARON
+0220 ; Lu # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222 ; Lu # LATIN CAPITAL LETTER OU
+0224 ; Lu # LATIN CAPITAL LETTER Z WITH HOOK
+0226 ; Lu # LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228 ; Lu # LATIN CAPITAL LETTER E WITH CEDILLA
+022A ; Lu # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C ; Lu # LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E ; Lu # LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230 ; Lu # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232 ; Lu # LATIN CAPITAL LETTER Y WITH MACRON
+023A..023B ; Lu # [2] LATIN CAPITAL LETTER A WITH STROKE..LATIN CAPITAL LETTER C WITH STROKE
+023D..023E ; Lu # [2] LATIN CAPITAL LETTER L WITH BAR..LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+0241 ; Lu # LATIN CAPITAL LETTER GLOTTAL STOP
+0243..0246 ; Lu # [4] LATIN CAPITAL LETTER B WITH STROKE..LATIN CAPITAL LETTER E WITH STROKE
+0248 ; Lu # LATIN CAPITAL LETTER J WITH STROKE
+024A ; Lu # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+024C ; Lu # LATIN CAPITAL LETTER R WITH STROKE
+024E ; Lu # LATIN CAPITAL LETTER Y WITH STROKE
+0370 ; Lu # GREEK CAPITAL LETTER HETA
+0372 ; Lu # GREEK CAPITAL LETTER ARCHAIC SAMPI
+0376 ; Lu # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+0386 ; Lu # GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Lu # [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Lu # GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..038F ; Lu # [2] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER OMEGA WITH TONOS
+0391..03A1 ; Lu # [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO
+03A3..03AB ; Lu # [9] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03CF ; Lu # GREEK CAPITAL KAI SYMBOL
+03D2..03D4 ; Lu # [3] GREEK UPSILON WITH HOOK SYMBOL..GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL
+03D8 ; Lu # GREEK LETTER ARCHAIC KOPPA
+03DA ; Lu # GREEK LETTER STIGMA
+03DC ; Lu # GREEK LETTER DIGAMMA
+03DE ; Lu # GREEK LETTER KOPPA
+03E0 ; Lu # GREEK LETTER SAMPI
+03E2 ; Lu # COPTIC CAPITAL LETTER SHEI
+03E4 ; Lu # COPTIC CAPITAL LETTER FEI
+03E6 ; Lu # COPTIC CAPITAL LETTER KHEI
+03E8 ; Lu # COPTIC CAPITAL LETTER HORI
+03EA ; Lu # COPTIC CAPITAL LETTER GANGIA
+03EC ; Lu # COPTIC CAPITAL LETTER SHIMA
+03EE ; Lu # COPTIC CAPITAL LETTER DEI
+03F4 ; Lu # GREEK CAPITAL THETA SYMBOL
+03F7 ; Lu # GREEK CAPITAL LETTER SHO
+03F9..03FA ; Lu # [2] GREEK CAPITAL LUNATE SIGMA SYMBOL..GREEK CAPITAL LETTER SAN
+03FD..042F ; Lu # [51] GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL..CYRILLIC CAPITAL LETTER YA
+0460 ; Lu # CYRILLIC CAPITAL LETTER OMEGA
+0462 ; Lu # CYRILLIC CAPITAL LETTER YAT
+0464 ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED E
+0466 ; Lu # CYRILLIC CAPITAL LETTER LITTLE YUS
+0468 ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A ; Lu # CYRILLIC CAPITAL LETTER BIG YUS
+046C ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E ; Lu # CYRILLIC CAPITAL LETTER KSI
+0470 ; Lu # CYRILLIC CAPITAL LETTER PSI
+0472 ; Lu # CYRILLIC CAPITAL LETTER FITA
+0474 ; Lu # CYRILLIC CAPITAL LETTER IZHITSA
+0476 ; Lu # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478 ; Lu # CYRILLIC CAPITAL LETTER UK
+047A ; Lu # CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C ; Lu # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E ; Lu # CYRILLIC CAPITAL LETTER OT
+0480 ; Lu # CYRILLIC CAPITAL LETTER KOPPA
+048A ; Lu # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C ; Lu # CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E ; Lu # CYRILLIC CAPITAL LETTER ER WITH TICK
+0490 ; Lu # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492 ; Lu # CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494 ; Lu # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496 ; Lu # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498 ; Lu # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A ; Lu # CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C ; Lu # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E ; Lu # CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0 ; Lu # CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2 ; Lu # CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4 ; Lu # CYRILLIC CAPITAL LIGATURE EN GHE
+04A6 ; Lu # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8 ; Lu # CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA ; Lu # CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC ; Lu # CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE ; Lu # CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0 ; Lu # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2 ; Lu # CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4 ; Lu # CYRILLIC CAPITAL LIGATURE TE TSE
+04B6 ; Lu # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8 ; Lu # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA ; Lu # CYRILLIC CAPITAL LETTER SHHA
+04BC ; Lu # CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE ; Lu # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C0..04C1 ; Lu # [2] CYRILLIC LETTER PALOCHKA..CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3 ; Lu # CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5 ; Lu # CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7 ; Lu # CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9 ; Lu # CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB ; Lu # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD ; Lu # CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0 ; Lu # CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2 ; Lu # CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4 ; Lu # CYRILLIC CAPITAL LIGATURE A IE
+04D6 ; Lu # CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8 ; Lu # CYRILLIC CAPITAL LETTER SCHWA
+04DA ; Lu # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC ; Lu # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE ; Lu # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0 ; Lu # CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2 ; Lu # CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4 ; Lu # CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6 ; Lu # CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8 ; Lu # CYRILLIC CAPITAL LETTER BARRED O
+04EA ; Lu # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC ; Lu # CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE ; Lu # CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0 ; Lu # CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2 ; Lu # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4 ; Lu # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6 ; Lu # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8 ; Lu # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+04FA ; Lu # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+04FC ; Lu # CYRILLIC CAPITAL LETTER HA WITH HOOK
+04FE ; Lu # CYRILLIC CAPITAL LETTER HA WITH STROKE
+0500 ; Lu # CYRILLIC CAPITAL LETTER KOMI DE
+0502 ; Lu # CYRILLIC CAPITAL LETTER KOMI DJE
+0504 ; Lu # CYRILLIC CAPITAL LETTER KOMI ZJE
+0506 ; Lu # CYRILLIC CAPITAL LETTER KOMI DZJE
+0508 ; Lu # CYRILLIC CAPITAL LETTER KOMI LJE
+050A ; Lu # CYRILLIC CAPITAL LETTER KOMI NJE
+050C ; Lu # CYRILLIC CAPITAL LETTER KOMI SJE
+050E ; Lu # CYRILLIC CAPITAL LETTER KOMI TJE
+0510 ; Lu # CYRILLIC CAPITAL LETTER REVERSED ZE
+0512 ; Lu # CYRILLIC CAPITAL LETTER EL WITH HOOK
+0514 ; Lu # CYRILLIC CAPITAL LETTER LHA
+0516 ; Lu # CYRILLIC CAPITAL LETTER RHA
+0518 ; Lu # CYRILLIC CAPITAL LETTER YAE
+051A ; Lu # CYRILLIC CAPITAL LETTER QA
+051C ; Lu # CYRILLIC CAPITAL LETTER WE
+051E ; Lu # CYRILLIC CAPITAL LETTER ALEUT KA
+0520 ; Lu # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
+0522 ; Lu # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
+0531..0556 ; Lu # [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+10A0..10C5 ; Lu # [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+1E00 ; Lu # LATIN CAPITAL LETTER A WITH RING BELOW
+1E02 ; Lu # LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04 ; Lu # LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06 ; Lu # LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08 ; Lu # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A ; Lu # LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C ; Lu # LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E ; Lu # LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10 ; Lu # LATIN CAPITAL LETTER D WITH CEDILLA
+1E12 ; Lu # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14 ; Lu # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16 ; Lu # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18 ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A ; Lu # LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C ; Lu # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E ; Lu # LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20 ; Lu # LATIN CAPITAL LETTER G WITH MACRON
+1E22 ; Lu # LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24 ; Lu # LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26 ; Lu # LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28 ; Lu # LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A ; Lu # LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C ; Lu # LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E ; Lu # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30 ; Lu # LATIN CAPITAL LETTER K WITH ACUTE
+1E32 ; Lu # LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34 ; Lu # LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36 ; Lu # LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38 ; Lu # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A ; Lu # LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C ; Lu # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E ; Lu # LATIN CAPITAL LETTER M WITH ACUTE
+1E40 ; Lu # LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42 ; Lu # LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44 ; Lu # LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46 ; Lu # LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48 ; Lu # LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A ; Lu # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C ; Lu # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E ; Lu # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50 ; Lu # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52 ; Lu # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54 ; Lu # LATIN CAPITAL LETTER P WITH ACUTE
+1E56 ; Lu # LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58 ; Lu # LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A ; Lu # LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C ; Lu # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E ; Lu # LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60 ; Lu # LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62 ; Lu # LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64 ; Lu # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66 ; Lu # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68 ; Lu # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A ; Lu # LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C ; Lu # LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E ; Lu # LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70 ; Lu # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72 ; Lu # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74 ; Lu # LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76 ; Lu # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78 ; Lu # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A ; Lu # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C ; Lu # LATIN CAPITAL LETTER V WITH TILDE
+1E7E ; Lu # LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80 ; Lu # LATIN CAPITAL LETTER W WITH GRAVE
+1E82 ; Lu # LATIN CAPITAL LETTER W WITH ACUTE
+1E84 ; Lu # LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86 ; Lu # LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88 ; Lu # LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A ; Lu # LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C ; Lu # LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E ; Lu # LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90 ; Lu # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92 ; Lu # LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94 ; Lu # LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E9E ; Lu # LATIN CAPITAL LETTER SHARP S
+1EA0 ; Lu # LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2 ; Lu # LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4 ; Lu # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6 ; Lu # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8 ; Lu # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA ; Lu # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC ; Lu # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE ; Lu # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0 ; Lu # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2 ; Lu # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4 ; Lu # LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6 ; Lu # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8 ; Lu # LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA ; Lu # LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC ; Lu # LATIN CAPITAL LETTER E WITH TILDE
+1EBE ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0 ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2 ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4 ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6 ; Lu # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8 ; Lu # LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA ; Lu # LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC ; Lu # LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE ; Lu # LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0 ; Lu # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2 ; Lu # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4 ; Lu # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6 ; Lu # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8 ; Lu # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA ; Lu # LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC ; Lu # LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE ; Lu # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0 ; Lu # LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2 ; Lu # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4 ; Lu # LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6 ; Lu # LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8 ; Lu # LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA ; Lu # LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC ; Lu # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE ; Lu # LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0 ; Lu # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2 ; Lu # LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4 ; Lu # LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6 ; Lu # LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8 ; Lu # LATIN CAPITAL LETTER Y WITH TILDE
+1EFA ; Lu # LATIN CAPITAL LETTER MIDDLE-WELSH LL
+1EFC ; Lu # LATIN CAPITAL LETTER MIDDLE-WELSH V
+1EFE ; Lu # LATIN CAPITAL LETTER Y WITH LOOP
+1F08..1F0F ; Lu # [8] GREEK CAPITAL LETTER ALPHA WITH PSILI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18..1F1D ; Lu # [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28..1F2F ; Lu # [8] GREEK CAPITAL LETTER ETA WITH PSILI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38..1F3F ; Lu # [8] GREEK CAPITAL LETTER IOTA WITH PSILI..GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48..1F4D ; Lu # [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F59 ; Lu # GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Lu # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Lu # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F ; Lu # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68..1F6F ; Lu # [8] GREEK CAPITAL LETTER OMEGA WITH PSILI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1FB8..1FBB ; Lu # [4] GREEK CAPITAL LETTER ALPHA WITH VRACHY..GREEK CAPITAL LETTER ALPHA WITH OXIA
+1FC8..1FCB ; Lu # [4] GREEK CAPITAL LETTER EPSILON WITH VARIA..GREEK CAPITAL LETTER ETA WITH OXIA
+1FD8..1FDB ; Lu # [4] GREEK CAPITAL LETTER IOTA WITH VRACHY..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE8..1FEC ; Lu # [5] GREEK CAPITAL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FF8..1FFB ; Lu # [4] GREEK CAPITAL LETTER OMICRON WITH VARIA..GREEK CAPITAL LETTER OMEGA WITH OXIA
+2102 ; Lu # DOUBLE-STRUCK CAPITAL C
+2107 ; Lu # EULER CONSTANT
+210B..210D ; Lu # [3] SCRIPT CAPITAL H..DOUBLE-STRUCK CAPITAL H
+2110..2112 ; Lu # [3] SCRIPT CAPITAL I..SCRIPT CAPITAL L
+2115 ; Lu # DOUBLE-STRUCK CAPITAL N
+2119..211D ; Lu # [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+2124 ; Lu # DOUBLE-STRUCK CAPITAL Z
+2126 ; Lu # OHM SIGN
+2128 ; Lu # BLACK-LETTER CAPITAL Z
+212A..212D ; Lu # [4] KELVIN SIGN..BLACK-LETTER CAPITAL C
+2130..2133 ; Lu # [4] SCRIPT CAPITAL E..SCRIPT CAPITAL M
+213E..213F ; Lu # [2] DOUBLE-STRUCK CAPITAL GAMMA..DOUBLE-STRUCK CAPITAL PI
+2145 ; Lu # DOUBLE-STRUCK ITALIC CAPITAL D
+2183 ; Lu # ROMAN NUMERAL REVERSED ONE HUNDRED
+2C00..2C2E ; Lu # [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C60 ; Lu # LATIN CAPITAL LETTER L WITH DOUBLE BAR
+2C62..2C64 ; Lu # [3] LATIN CAPITAL LETTER L WITH MIDDLE TILDE..LATIN CAPITAL LETTER R WITH TAIL
+2C67 ; Lu # LATIN CAPITAL LETTER H WITH DESCENDER
+2C69 ; Lu # LATIN CAPITAL LETTER K WITH DESCENDER
+2C6B ; Lu # LATIN CAPITAL LETTER Z WITH DESCENDER
+2C6D..2C6F ; Lu # [3] LATIN CAPITAL LETTER ALPHA..LATIN CAPITAL LETTER TURNED A
+2C72 ; Lu # LATIN CAPITAL LETTER W WITH HOOK
+2C75 ; Lu # LATIN CAPITAL LETTER HALF H
+2C80 ; Lu # COPTIC CAPITAL LETTER ALFA
+2C82 ; Lu # COPTIC CAPITAL LETTER VIDA
+2C84 ; Lu # COPTIC CAPITAL LETTER GAMMA
+2C86 ; Lu # COPTIC CAPITAL LETTER DALDA
+2C88 ; Lu # COPTIC CAPITAL LETTER EIE
+2C8A ; Lu # COPTIC CAPITAL LETTER SOU
+2C8C ; Lu # COPTIC CAPITAL LETTER ZATA
+2C8E ; Lu # COPTIC CAPITAL LETTER HATE
+2C90 ; Lu # COPTIC CAPITAL LETTER THETHE
+2C92 ; Lu # COPTIC CAPITAL LETTER IAUDA
+2C94 ; Lu # COPTIC CAPITAL LETTER KAPA
+2C96 ; Lu # COPTIC CAPITAL LETTER LAULA
+2C98 ; Lu # COPTIC CAPITAL LETTER MI
+2C9A ; Lu # COPTIC CAPITAL LETTER NI
+2C9C ; Lu # COPTIC CAPITAL LETTER KSI
+2C9E ; Lu # COPTIC CAPITAL LETTER O
+2CA0 ; Lu # COPTIC CAPITAL LETTER PI
+2CA2 ; Lu # COPTIC CAPITAL LETTER RO
+2CA4 ; Lu # COPTIC CAPITAL LETTER SIMA
+2CA6 ; Lu # COPTIC CAPITAL LETTER TAU
+2CA8 ; Lu # COPTIC CAPITAL LETTER UA
+2CAA ; Lu # COPTIC CAPITAL LETTER FI
+2CAC ; Lu # COPTIC CAPITAL LETTER KHI
+2CAE ; Lu # COPTIC CAPITAL LETTER PSI
+2CB0 ; Lu # COPTIC CAPITAL LETTER OOU
+2CB2 ; Lu # COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6 ; Lu # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8 ; Lu # COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA ; Lu # COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC ; Lu # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE ; Lu # COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0 ; Lu # COPTIC CAPITAL LETTER SAMPI
+2CC2 ; Lu # COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8 ; Lu # COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA ; Lu # COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC ; Lu # COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE ; Lu # COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0 ; Lu # COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8 ; Lu # COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA ; Lu # COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC ; Lu # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE ; Lu # COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0 ; Lu # COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2 ; Lu # COPTIC CAPITAL LETTER OLD NUBIAN WAU
+A640 ; Lu # CYRILLIC CAPITAL LETTER ZEMLYA
+A642 ; Lu # CYRILLIC CAPITAL LETTER DZELO
+A644 ; Lu # CYRILLIC CAPITAL LETTER REVERSED DZE
+A646 ; Lu # CYRILLIC CAPITAL LETTER IOTA
+A648 ; Lu # CYRILLIC CAPITAL LETTER DJERV
+A64A ; Lu # CYRILLIC CAPITAL LETTER MONOGRAPH UK
+A64C ; Lu # CYRILLIC CAPITAL LETTER BROAD OMEGA
+A64E ; Lu # CYRILLIC CAPITAL LETTER NEUTRAL YER
+A650 ; Lu # CYRILLIC CAPITAL LETTER YERU WITH BACK YER
+A652 ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED YAT
+A654 ; Lu # CYRILLIC CAPITAL LETTER REVERSED YU
+A656 ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED A
+A658 ; Lu # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
+A65A ; Lu # CYRILLIC CAPITAL LETTER BLENDED YUS
+A65C ; Lu # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
+A65E ; Lu # CYRILLIC CAPITAL LETTER YN
+A662 ; Lu # CYRILLIC CAPITAL LETTER SOFT DE
+A664 ; Lu # CYRILLIC CAPITAL LETTER SOFT EL
+A666 ; Lu # CYRILLIC CAPITAL LETTER SOFT EM
+A668 ; Lu # CYRILLIC CAPITAL LETTER MONOCULAR O
+A66A ; Lu # CYRILLIC CAPITAL LETTER BINOCULAR O
+A66C ; Lu # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
+A680 ; Lu # CYRILLIC CAPITAL LETTER DWE
+A682 ; Lu # CYRILLIC CAPITAL LETTER DZWE
+A684 ; Lu # CYRILLIC CAPITAL LETTER ZHWE
+A686 ; Lu # CYRILLIC CAPITAL LETTER CCHE
+A688 ; Lu # CYRILLIC CAPITAL LETTER DZZE
+A68A ; Lu # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
+A68C ; Lu # CYRILLIC CAPITAL LETTER TWE
+A68E ; Lu # CYRILLIC CAPITAL LETTER TSWE
+A690 ; Lu # CYRILLIC CAPITAL LETTER TSSE
+A692 ; Lu # CYRILLIC CAPITAL LETTER TCHE
+A694 ; Lu # CYRILLIC CAPITAL LETTER HWE
+A696 ; Lu # CYRILLIC CAPITAL LETTER SHWE
+A722 ; Lu # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
+A724 ; Lu # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
+A726 ; Lu # LATIN CAPITAL LETTER HENG
+A728 ; Lu # LATIN CAPITAL LETTER TZ
+A72A ; Lu # LATIN CAPITAL LETTER TRESILLO
+A72C ; Lu # LATIN CAPITAL LETTER CUATRILLO
+A72E ; Lu # LATIN CAPITAL LETTER CUATRILLO WITH COMMA
+A732 ; Lu # LATIN CAPITAL LETTER AA
+A734 ; Lu # LATIN CAPITAL LETTER AO
+A736 ; Lu # LATIN CAPITAL LETTER AU
+A738 ; Lu # LATIN CAPITAL LETTER AV
+A73A ; Lu # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+A73C ; Lu # LATIN CAPITAL LETTER AY
+A73E ; Lu # LATIN CAPITAL LETTER REVERSED C WITH DOT
+A740 ; Lu # LATIN CAPITAL LETTER K WITH STROKE
+A742 ; Lu # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+A744 ; Lu # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+A746 ; Lu # LATIN CAPITAL LETTER BROKEN L
+A748 ; Lu # LATIN CAPITAL LETTER L WITH HIGH STROKE
+A74A ; Lu # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+A74C ; Lu # LATIN CAPITAL LETTER O WITH LOOP
+A74E ; Lu # LATIN CAPITAL LETTER OO
+A750 ; Lu # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+A752 ; Lu # LATIN CAPITAL LETTER P WITH FLOURISH
+A754 ; Lu # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+A756 ; Lu # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+A758 ; Lu # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+A75A ; Lu # LATIN CAPITAL LETTER R ROTUNDA
+A75C ; Lu # LATIN CAPITAL LETTER RUM ROTUNDA
+A75E ; Lu # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+A760 ; Lu # LATIN CAPITAL LETTER VY
+A762 ; Lu # LATIN CAPITAL LETTER VISIGOTHIC Z
+A764 ; Lu # LATIN CAPITAL LETTER THORN WITH STROKE
+A766 ; Lu # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
+A768 ; Lu # LATIN CAPITAL LETTER VEND
+A76A ; Lu # LATIN CAPITAL LETTER ET
+A76C ; Lu # LATIN CAPITAL LETTER IS
+A76E ; Lu # LATIN CAPITAL LETTER CON
+A779 ; Lu # LATIN CAPITAL LETTER INSULAR D
+A77B ; Lu # LATIN CAPITAL LETTER INSULAR F
+A77D..A77E ; Lu # [2] LATIN CAPITAL LETTER INSULAR G..LATIN CAPITAL LETTER TURNED INSULAR G
+A780 ; Lu # LATIN CAPITAL LETTER TURNED L
+A782 ; Lu # LATIN CAPITAL LETTER INSULAR R
+A784 ; Lu # LATIN CAPITAL LETTER INSULAR S
+A786 ; Lu # LATIN CAPITAL LETTER INSULAR T
+A78B ; Lu # LATIN CAPITAL LETTER SALTILLO
+FF21..FF3A ; Lu # [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+10400..10427 ; Lu # [40] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER EW
+1D400..1D419 ; Lu # [26] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL BOLD CAPITAL Z
+1D434..1D44D ; Lu # [26] MATHEMATICAL ITALIC CAPITAL A..MATHEMATICAL ITALIC CAPITAL Z
+1D468..1D481 ; Lu # [26] MATHEMATICAL BOLD ITALIC CAPITAL A..MATHEMATICAL BOLD ITALIC CAPITAL Z
+1D49C ; Lu # MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Lu # [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Lu # MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Lu # [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Lu # [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B5 ; Lu # [8] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT CAPITAL Z
+1D4D0..1D4E9 ; Lu # [26] MATHEMATICAL BOLD SCRIPT CAPITAL A..MATHEMATICAL BOLD SCRIPT CAPITAL Z
+1D504..1D505 ; Lu # [2] MATHEMATICAL FRAKTUR CAPITAL A..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Lu # [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Lu # [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Lu # [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D538..1D539 ; Lu # [2] MATHEMATICAL DOUBLE-STRUCK CAPITAL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Lu # [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Lu # [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Lu # MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Lu # [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D56C..1D585 ; Lu # [26] MATHEMATICAL BOLD FRAKTUR CAPITAL A..MATHEMATICAL BOLD FRAKTUR CAPITAL Z
+1D5A0..1D5B9 ; Lu # [26] MATHEMATICAL SANS-SERIF CAPITAL A..MATHEMATICAL SANS-SERIF CAPITAL Z
+1D5D4..1D5ED ; Lu # [26] MATHEMATICAL SANS-SERIF BOLD CAPITAL A..MATHEMATICAL SANS-SERIF BOLD CAPITAL Z
+1D608..1D621 ; Lu # [26] MATHEMATICAL SANS-SERIF ITALIC CAPITAL A..MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z
+1D63C..1D655 ; Lu # [26] MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z
+1D670..1D689 ; Lu # [26] MATHEMATICAL MONOSPACE CAPITAL A..MATHEMATICAL MONOSPACE CAPITAL Z
+1D6A8..1D6C0 ; Lu # [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6E2..1D6FA ; Lu # [25] MATHEMATICAL ITALIC CAPITAL ALPHA..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D71C..1D734 ; Lu # [25] MATHEMATICAL BOLD ITALIC CAPITAL ALPHA..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D756..1D76E ; Lu # [25] MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D790..1D7A8 ; Lu # [25] MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7CA ; Lu # MATHEMATICAL BOLD CAPITAL DIGAMMA
+
+# Total code points: 1421
+
+# ================================================
+
+# General_Category=Lowercase_Letter
+
+0061..007A ; Ll # [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; Ll # FEMININE ORDINAL INDICATOR
+00B5 ; Ll # MICRO SIGN
+00BA ; Ll # MASCULINE ORDINAL INDICATOR
+00DF..00F6 ; Ll # [24] LATIN SMALL LETTER SHARP S..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..00FF ; Ll # [8] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER Y WITH DIAERESIS
+0101 ; Ll # LATIN SMALL LETTER A WITH MACRON
+0103 ; Ll # LATIN SMALL LETTER A WITH BREVE
+0105 ; Ll # LATIN SMALL LETTER A WITH OGONEK
+0107 ; Ll # LATIN SMALL LETTER C WITH ACUTE
+0109 ; Ll # LATIN SMALL LETTER C WITH CIRCUMFLEX
+010B ; Ll # LATIN SMALL LETTER C WITH DOT ABOVE
+010D ; Ll # LATIN SMALL LETTER C WITH CARON
+010F ; Ll # LATIN SMALL LETTER D WITH CARON
+0111 ; Ll # LATIN SMALL LETTER D WITH STROKE
+0113 ; Ll # LATIN SMALL LETTER E WITH MACRON
+0115 ; Ll # LATIN SMALL LETTER E WITH BREVE
+0117 ; Ll # LATIN SMALL LETTER E WITH DOT ABOVE
+0119 ; Ll # LATIN SMALL LETTER E WITH OGONEK
+011B ; Ll # LATIN SMALL LETTER E WITH CARON
+011D ; Ll # LATIN SMALL LETTER G WITH CIRCUMFLEX
+011F ; Ll # LATIN SMALL LETTER G WITH BREVE
+0121 ; Ll # LATIN SMALL LETTER G WITH DOT ABOVE
+0123 ; Ll # LATIN SMALL LETTER G WITH CEDILLA
+0125 ; Ll # LATIN SMALL LETTER H WITH CIRCUMFLEX
+0127 ; Ll # LATIN SMALL LETTER H WITH STROKE
+0129 ; Ll # LATIN SMALL LETTER I WITH TILDE
+012B ; Ll # LATIN SMALL LETTER I WITH MACRON
+012D ; Ll # LATIN SMALL LETTER I WITH BREVE
+012F ; Ll # LATIN SMALL LETTER I WITH OGONEK
+0131 ; Ll # LATIN SMALL LETTER DOTLESS I
+0133 ; Ll # LATIN SMALL LIGATURE IJ
+0135 ; Ll # LATIN SMALL LETTER J WITH CIRCUMFLEX
+0137..0138 ; Ll # [2] LATIN SMALL LETTER K WITH CEDILLA..LATIN SMALL LETTER KRA
+013A ; Ll # LATIN SMALL LETTER L WITH ACUTE
+013C ; Ll # LATIN SMALL LETTER L WITH CEDILLA
+013E ; Ll # LATIN SMALL LETTER L WITH CARON
+0140 ; Ll # LATIN SMALL LETTER L WITH MIDDLE DOT
+0142 ; Ll # LATIN SMALL LETTER L WITH STROKE
+0144 ; Ll # LATIN SMALL LETTER N WITH ACUTE
+0146 ; Ll # LATIN SMALL LETTER N WITH CEDILLA
+0148..0149 ; Ll # [2] LATIN SMALL LETTER N WITH CARON..LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014B ; Ll # LATIN SMALL LETTER ENG
+014D ; Ll # LATIN SMALL LETTER O WITH MACRON
+014F ; Ll # LATIN SMALL LETTER O WITH BREVE
+0151 ; Ll # LATIN SMALL LETTER O WITH DOUBLE ACUTE
+0153 ; Ll # LATIN SMALL LIGATURE OE
+0155 ; Ll # LATIN SMALL LETTER R WITH ACUTE
+0157 ; Ll # LATIN SMALL LETTER R WITH CEDILLA
+0159 ; Ll # LATIN SMALL LETTER R WITH CARON
+015B ; Ll # LATIN SMALL LETTER S WITH ACUTE
+015D ; Ll # LATIN SMALL LETTER S WITH CIRCUMFLEX
+015F ; Ll # LATIN SMALL LETTER S WITH CEDILLA
+0161 ; Ll # LATIN SMALL LETTER S WITH CARON
+0163 ; Ll # LATIN SMALL LETTER T WITH CEDILLA
+0165 ; Ll # LATIN SMALL LETTER T WITH CARON
+0167 ; Ll # LATIN SMALL LETTER T WITH STROKE
+0169 ; Ll # LATIN SMALL LETTER U WITH TILDE
+016B ; Ll # LATIN SMALL LETTER U WITH MACRON
+016D ; Ll # LATIN SMALL LETTER U WITH BREVE
+016F ; Ll # LATIN SMALL LETTER U WITH RING ABOVE
+0171 ; Ll # LATIN SMALL LETTER U WITH DOUBLE ACUTE
+0173 ; Ll # LATIN SMALL LETTER U WITH OGONEK
+0175 ; Ll # LATIN SMALL LETTER W WITH CIRCUMFLEX
+0177 ; Ll # LATIN SMALL LETTER Y WITH CIRCUMFLEX
+017A ; Ll # LATIN SMALL LETTER Z WITH ACUTE
+017C ; Ll # LATIN SMALL LETTER Z WITH DOT ABOVE
+017E..0180 ; Ll # [3] LATIN SMALL LETTER Z WITH CARON..LATIN SMALL LETTER B WITH STROKE
+0183 ; Ll # LATIN SMALL LETTER B WITH TOPBAR
+0185 ; Ll # LATIN SMALL LETTER TONE SIX
+0188 ; Ll # LATIN SMALL LETTER C WITH HOOK
+018C..018D ; Ll # [2] LATIN SMALL LETTER D WITH TOPBAR..LATIN SMALL LETTER TURNED DELTA
+0192 ; Ll # LATIN SMALL LETTER F WITH HOOK
+0195 ; Ll # LATIN SMALL LETTER HV
+0199..019B ; Ll # [3] LATIN SMALL LETTER K WITH HOOK..LATIN SMALL LETTER LAMBDA WITH STROKE
+019E ; Ll # LATIN SMALL LETTER N WITH LONG RIGHT LEG
+01A1 ; Ll # LATIN SMALL LETTER O WITH HORN
+01A3 ; Ll # LATIN SMALL LETTER OI
+01A5 ; Ll # LATIN SMALL LETTER P WITH HOOK
+01A8 ; Ll # LATIN SMALL LETTER TONE TWO
+01AA..01AB ; Ll # [2] LATIN LETTER REVERSED ESH LOOP..LATIN SMALL LETTER T WITH PALATAL HOOK
+01AD ; Ll # LATIN SMALL LETTER T WITH HOOK
+01B0 ; Ll # LATIN SMALL LETTER U WITH HORN
+01B4 ; Ll # LATIN SMALL LETTER Y WITH HOOK
+01B6 ; Ll # LATIN SMALL LETTER Z WITH STROKE
+01B9..01BA ; Ll # [2] LATIN SMALL LETTER EZH REVERSED..LATIN SMALL LETTER EZH WITH TAIL
+01BD..01BF ; Ll # [3] LATIN SMALL LETTER TONE FIVE..LATIN LETTER WYNN
+01C6 ; Ll # LATIN SMALL LETTER DZ WITH CARON
+01C9 ; Ll # LATIN SMALL LETTER LJ
+01CC ; Ll # LATIN SMALL LETTER NJ
+01CE ; Ll # LATIN SMALL LETTER A WITH CARON
+01D0 ; Ll # LATIN SMALL LETTER I WITH CARON
+01D2 ; Ll # LATIN SMALL LETTER O WITH CARON
+01D4 ; Ll # LATIN SMALL LETTER U WITH CARON
+01D6 ; Ll # LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+01D8 ; Ll # LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+01DA ; Ll # LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+01DC..01DD ; Ll # [2] LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE..LATIN SMALL LETTER TURNED E
+01DF ; Ll # LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+01E1 ; Ll # LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+01E3 ; Ll # LATIN SMALL LETTER AE WITH MACRON
+01E5 ; Ll # LATIN SMALL LETTER G WITH STROKE
+01E7 ; Ll # LATIN SMALL LETTER G WITH CARON
+01E9 ; Ll # LATIN SMALL LETTER K WITH CARON
+01EB ; Ll # LATIN SMALL LETTER O WITH OGONEK
+01ED ; Ll # LATIN SMALL LETTER O WITH OGONEK AND MACRON
+01EF..01F0 ; Ll # [2] LATIN SMALL LETTER EZH WITH CARON..LATIN SMALL LETTER J WITH CARON
+01F3 ; Ll # LATIN SMALL LETTER DZ
+01F5 ; Ll # LATIN SMALL LETTER G WITH ACUTE
+01F9 ; Ll # LATIN SMALL LETTER N WITH GRAVE
+01FB ; Ll # LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+01FD ; Ll # LATIN SMALL LETTER AE WITH ACUTE
+01FF ; Ll # LATIN SMALL LETTER O WITH STROKE AND ACUTE
+0201 ; Ll # LATIN SMALL LETTER A WITH DOUBLE GRAVE
+0203 ; Ll # LATIN SMALL LETTER A WITH INVERTED BREVE
+0205 ; Ll # LATIN SMALL LETTER E WITH DOUBLE GRAVE
+0207 ; Ll # LATIN SMALL LETTER E WITH INVERTED BREVE
+0209 ; Ll # LATIN SMALL LETTER I WITH DOUBLE GRAVE
+020B ; Ll # LATIN SMALL LETTER I WITH INVERTED BREVE
+020D ; Ll # LATIN SMALL LETTER O WITH DOUBLE GRAVE
+020F ; Ll # LATIN SMALL LETTER O WITH INVERTED BREVE
+0211 ; Ll # LATIN SMALL LETTER R WITH DOUBLE GRAVE
+0213 ; Ll # LATIN SMALL LETTER R WITH INVERTED BREVE
+0215 ; Ll # LATIN SMALL LETTER U WITH DOUBLE GRAVE
+0217 ; Ll # LATIN SMALL LETTER U WITH INVERTED BREVE
+0219 ; Ll # LATIN SMALL LETTER S WITH COMMA BELOW
+021B ; Ll # LATIN SMALL LETTER T WITH COMMA BELOW
+021D ; Ll # LATIN SMALL LETTER YOGH
+021F ; Ll # LATIN SMALL LETTER H WITH CARON
+0221 ; Ll # LATIN SMALL LETTER D WITH CURL
+0223 ; Ll # LATIN SMALL LETTER OU
+0225 ; Ll # LATIN SMALL LETTER Z WITH HOOK
+0227 ; Ll # LATIN SMALL LETTER A WITH DOT ABOVE
+0229 ; Ll # LATIN SMALL LETTER E WITH CEDILLA
+022B ; Ll # LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+022D ; Ll # LATIN SMALL LETTER O WITH TILDE AND MACRON
+022F ; Ll # LATIN SMALL LETTER O WITH DOT ABOVE
+0231 ; Ll # LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+0233..0239 ; Ll # [7] LATIN SMALL LETTER Y WITH MACRON..LATIN SMALL LETTER QP DIGRAPH
+023C ; Ll # LATIN SMALL LETTER C WITH STROKE
+023F..0240 ; Ll # [2] LATIN SMALL LETTER S WITH SWASH TAIL..LATIN SMALL LETTER Z WITH SWASH TAIL
+0242 ; Ll # LATIN SMALL LETTER GLOTTAL STOP
+0247 ; Ll # LATIN SMALL LETTER E WITH STROKE
+0249 ; Ll # LATIN SMALL LETTER J WITH STROKE
+024B ; Ll # LATIN SMALL LETTER Q WITH HOOK TAIL
+024D ; Ll # LATIN SMALL LETTER R WITH STROKE
+024F..0293 ; Ll # [69] LATIN SMALL LETTER Y WITH STROKE..LATIN SMALL LETTER EZH WITH CURL
+0295..02AF ; Ll # [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+0371 ; Ll # GREEK SMALL LETTER HETA
+0373 ; Ll # GREEK SMALL LETTER ARCHAIC SAMPI
+0377 ; Ll # GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037B..037D ; Ll # [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0390 ; Ll # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+03AC..03CE ; Ll # [35] GREEK SMALL LETTER ALPHA WITH TONOS..GREEK SMALL LETTER OMEGA WITH TONOS
+03D0..03D1 ; Ll # [2] GREEK BETA SYMBOL..GREEK THETA SYMBOL
+03D5..03D7 ; Ll # [3] GREEK PHI SYMBOL..GREEK KAI SYMBOL
+03D9 ; Ll # GREEK SMALL LETTER ARCHAIC KOPPA
+03DB ; Ll # GREEK SMALL LETTER STIGMA
+03DD ; Ll # GREEK SMALL LETTER DIGAMMA
+03DF ; Ll # GREEK SMALL LETTER KOPPA
+03E1 ; Ll # GREEK SMALL LETTER SAMPI
+03E3 ; Ll # COPTIC SMALL LETTER SHEI
+03E5 ; Ll # COPTIC SMALL LETTER FEI
+03E7 ; Ll # COPTIC SMALL LETTER KHEI
+03E9 ; Ll # COPTIC SMALL LETTER HORI
+03EB ; Ll # COPTIC SMALL LETTER GANGIA
+03ED ; Ll # COPTIC SMALL LETTER SHIMA
+03EF..03F3 ; Ll # [5] COPTIC SMALL LETTER DEI..GREEK LETTER YOT
+03F5 ; Ll # GREEK LUNATE EPSILON SYMBOL
+03F8 ; Ll # GREEK SMALL LETTER SHO
+03FB..03FC ; Ll # [2] GREEK SMALL LETTER SAN..GREEK RHO WITH STROKE SYMBOL
+0430..045F ; Ll # [48] CYRILLIC SMALL LETTER A..CYRILLIC SMALL LETTER DZHE
+0461 ; Ll # CYRILLIC SMALL LETTER OMEGA
+0463 ; Ll # CYRILLIC SMALL LETTER YAT
+0465 ; Ll # CYRILLIC SMALL LETTER IOTIFIED E
+0467 ; Ll # CYRILLIC SMALL LETTER LITTLE YUS
+0469 ; Ll # CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
+046B ; Ll # CYRILLIC SMALL LETTER BIG YUS
+046D ; Ll # CYRILLIC SMALL LETTER IOTIFIED BIG YUS
+046F ; Ll # CYRILLIC SMALL LETTER KSI
+0471 ; Ll # CYRILLIC SMALL LETTER PSI
+0473 ; Ll # CYRILLIC SMALL LETTER FITA
+0475 ; Ll # CYRILLIC SMALL LETTER IZHITSA
+0477 ; Ll # CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0479 ; Ll # CYRILLIC SMALL LETTER UK
+047B ; Ll # CYRILLIC SMALL LETTER ROUND OMEGA
+047D ; Ll # CYRILLIC SMALL LETTER OMEGA WITH TITLO
+047F ; Ll # CYRILLIC SMALL LETTER OT
+0481 ; Ll # CYRILLIC SMALL LETTER KOPPA
+048B ; Ll # CYRILLIC SMALL LETTER SHORT I WITH TAIL
+048D ; Ll # CYRILLIC SMALL LETTER SEMISOFT SIGN
+048F ; Ll # CYRILLIC SMALL LETTER ER WITH TICK
+0491 ; Ll # CYRILLIC SMALL LETTER GHE WITH UPTURN
+0493 ; Ll # CYRILLIC SMALL LETTER GHE WITH STROKE
+0495 ; Ll # CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
+0497 ; Ll # CYRILLIC SMALL LETTER ZHE WITH DESCENDER
+0499 ; Ll # CYRILLIC SMALL LETTER ZE WITH DESCENDER
+049B ; Ll # CYRILLIC SMALL LETTER KA WITH DESCENDER
+049D ; Ll # CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
+049F ; Ll # CYRILLIC SMALL LETTER KA WITH STROKE
+04A1 ; Ll # CYRILLIC SMALL LETTER BASHKIR KA
+04A3 ; Ll # CYRILLIC SMALL LETTER EN WITH DESCENDER
+04A5 ; Ll # CYRILLIC SMALL LIGATURE EN GHE
+04A7 ; Ll # CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
+04A9 ; Ll # CYRILLIC SMALL LETTER ABKHASIAN HA
+04AB ; Ll # CYRILLIC SMALL LETTER ES WITH DESCENDER
+04AD ; Ll # CYRILLIC SMALL LETTER TE WITH DESCENDER
+04AF ; Ll # CYRILLIC SMALL LETTER STRAIGHT U
+04B1 ; Ll # CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+04B3 ; Ll # CYRILLIC SMALL LETTER HA WITH DESCENDER
+04B5 ; Ll # CYRILLIC SMALL LIGATURE TE TSE
+04B7 ; Ll # CYRILLIC SMALL LETTER CHE WITH DESCENDER
+04B9 ; Ll # CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
+04BB ; Ll # CYRILLIC SMALL LETTER SHHA
+04BD ; Ll # CYRILLIC SMALL LETTER ABKHASIAN CHE
+04BF ; Ll # CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
+04C2 ; Ll # CYRILLIC SMALL LETTER ZHE WITH BREVE
+04C4 ; Ll # CYRILLIC SMALL LETTER KA WITH HOOK
+04C6 ; Ll # CYRILLIC SMALL LETTER EL WITH TAIL
+04C8 ; Ll # CYRILLIC SMALL LETTER EN WITH HOOK
+04CA ; Ll # CYRILLIC SMALL LETTER EN WITH TAIL
+04CC ; Ll # CYRILLIC SMALL LETTER KHAKASSIAN CHE
+04CE..04CF ; Ll # [2] CYRILLIC SMALL LETTER EM WITH TAIL..CYRILLIC SMALL LETTER PALOCHKA
+04D1 ; Ll # CYRILLIC SMALL LETTER A WITH BREVE
+04D3 ; Ll # CYRILLIC SMALL LETTER A WITH DIAERESIS
+04D5 ; Ll # CYRILLIC SMALL LIGATURE A IE
+04D7 ; Ll # CYRILLIC SMALL LETTER IE WITH BREVE
+04D9 ; Ll # CYRILLIC SMALL LETTER SCHWA
+04DB ; Ll # CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
+04DD ; Ll # CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
+04DF ; Ll # CYRILLIC SMALL LETTER ZE WITH DIAERESIS
+04E1 ; Ll # CYRILLIC SMALL LETTER ABKHASIAN DZE
+04E3 ; Ll # CYRILLIC SMALL LETTER I WITH MACRON
+04E5 ; Ll # CYRILLIC SMALL LETTER I WITH DIAERESIS
+04E7 ; Ll # CYRILLIC SMALL LETTER O WITH DIAERESIS
+04E9 ; Ll # CYRILLIC SMALL LETTER BARRED O
+04EB ; Ll # CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
+04ED ; Ll # CYRILLIC SMALL LETTER E WITH DIAERESIS
+04EF ; Ll # CYRILLIC SMALL LETTER U WITH MACRON
+04F1 ; Ll # CYRILLIC SMALL LETTER U WITH DIAERESIS
+04F3 ; Ll # CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
+04F5 ; Ll # CYRILLIC SMALL LETTER CHE WITH DIAERESIS
+04F7 ; Ll # CYRILLIC SMALL LETTER GHE WITH DESCENDER
+04F9 ; Ll # CYRILLIC SMALL LETTER YERU WITH DIAERESIS
+04FB ; Ll # CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
+04FD ; Ll # CYRILLIC SMALL LETTER HA WITH HOOK
+04FF ; Ll # CYRILLIC SMALL LETTER HA WITH STROKE
+0501 ; Ll # CYRILLIC SMALL LETTER KOMI DE
+0503 ; Ll # CYRILLIC SMALL LETTER KOMI DJE
+0505 ; Ll # CYRILLIC SMALL LETTER KOMI ZJE
+0507 ; Ll # CYRILLIC SMALL LETTER KOMI DZJE
+0509 ; Ll # CYRILLIC SMALL LETTER KOMI LJE
+050B ; Ll # CYRILLIC SMALL LETTER KOMI NJE
+050D ; Ll # CYRILLIC SMALL LETTER KOMI SJE
+050F ; Ll # CYRILLIC SMALL LETTER KOMI TJE
+0511 ; Ll # CYRILLIC SMALL LETTER REVERSED ZE
+0513 ; Ll # CYRILLIC SMALL LETTER EL WITH HOOK
+0515 ; Ll # CYRILLIC SMALL LETTER LHA
+0517 ; Ll # CYRILLIC SMALL LETTER RHA
+0519 ; Ll # CYRILLIC SMALL LETTER YAE
+051B ; Ll # CYRILLIC SMALL LETTER QA
+051D ; Ll # CYRILLIC SMALL LETTER WE
+051F ; Ll # CYRILLIC SMALL LETTER ALEUT KA
+0521 ; Ll # CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK
+0523 ; Ll # CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+0561..0587 ; Ll # [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+1D00..1D2B ; Ll # [44] LATIN LETTER SMALL CAPITAL A..CYRILLIC LETTER SMALL CAPITAL EL
+1D62..1D77 ; Ll # [22] LATIN SUBSCRIPT SMALL LETTER I..LATIN SMALL LETTER TURNED G
+1D79..1D9A ; Ll # [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1E01 ; Ll # LATIN SMALL LETTER A WITH RING BELOW
+1E03 ; Ll # LATIN SMALL LETTER B WITH DOT ABOVE
+1E05 ; Ll # LATIN SMALL LETTER B WITH DOT BELOW
+1E07 ; Ll # LATIN SMALL LETTER B WITH LINE BELOW
+1E09 ; Ll # LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+1E0B ; Ll # LATIN SMALL LETTER D WITH DOT ABOVE
+1E0D ; Ll # LATIN SMALL LETTER D WITH DOT BELOW
+1E0F ; Ll # LATIN SMALL LETTER D WITH LINE BELOW
+1E11 ; Ll # LATIN SMALL LETTER D WITH CEDILLA
+1E13 ; Ll # LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+1E15 ; Ll # LATIN SMALL LETTER E WITH MACRON AND GRAVE
+1E17 ; Ll # LATIN SMALL LETTER E WITH MACRON AND ACUTE
+1E19 ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+1E1B ; Ll # LATIN SMALL LETTER E WITH TILDE BELOW
+1E1D ; Ll # LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+1E1F ; Ll # LATIN SMALL LETTER F WITH DOT ABOVE
+1E21 ; Ll # LATIN SMALL LETTER G WITH MACRON
+1E23 ; Ll # LATIN SMALL LETTER H WITH DOT ABOVE
+1E25 ; Ll # LATIN SMALL LETTER H WITH DOT BELOW
+1E27 ; Ll # LATIN SMALL LETTER H WITH DIAERESIS
+1E29 ; Ll # LATIN SMALL LETTER H WITH CEDILLA
+1E2B ; Ll # LATIN SMALL LETTER H WITH BREVE BELOW
+1E2D ; Ll # LATIN SMALL LETTER I WITH TILDE BELOW
+1E2F ; Ll # LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+1E31 ; Ll # LATIN SMALL LETTER K WITH ACUTE
+1E33 ; Ll # LATIN SMALL LETTER K WITH DOT BELOW
+1E35 ; Ll # LATIN SMALL LETTER K WITH LINE BELOW
+1E37 ; Ll # LATIN SMALL LETTER L WITH DOT BELOW
+1E39 ; Ll # LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+1E3B ; Ll # LATIN SMALL LETTER L WITH LINE BELOW
+1E3D ; Ll # LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+1E3F ; Ll # LATIN SMALL LETTER M WITH ACUTE
+1E41 ; Ll # LATIN SMALL LETTER M WITH DOT ABOVE
+1E43 ; Ll # LATIN SMALL LETTER M WITH DOT BELOW
+1E45 ; Ll # LATIN SMALL LETTER N WITH DOT ABOVE
+1E47 ; Ll # LATIN SMALL LETTER N WITH DOT BELOW
+1E49 ; Ll # LATIN SMALL LETTER N WITH LINE BELOW
+1E4B ; Ll # LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+1E4D ; Ll # LATIN SMALL LETTER O WITH TILDE AND ACUTE
+1E4F ; Ll # LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+1E51 ; Ll # LATIN SMALL LETTER O WITH MACRON AND GRAVE
+1E53 ; Ll # LATIN SMALL LETTER O WITH MACRON AND ACUTE
+1E55 ; Ll # LATIN SMALL LETTER P WITH ACUTE
+1E57 ; Ll # LATIN SMALL LETTER P WITH DOT ABOVE
+1E59 ; Ll # LATIN SMALL LETTER R WITH DOT ABOVE
+1E5B ; Ll # LATIN SMALL LETTER R WITH DOT BELOW
+1E5D ; Ll # LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+1E5F ; Ll # LATIN SMALL LETTER R WITH LINE BELOW
+1E61 ; Ll # LATIN SMALL LETTER S WITH DOT ABOVE
+1E63 ; Ll # LATIN SMALL LETTER S WITH DOT BELOW
+1E65 ; Ll # LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+1E67 ; Ll # LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+1E69 ; Ll # LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6B ; Ll # LATIN SMALL LETTER T WITH DOT ABOVE
+1E6D ; Ll # LATIN SMALL LETTER T WITH DOT BELOW
+1E6F ; Ll # LATIN SMALL LETTER T WITH LINE BELOW
+1E71 ; Ll # LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+1E73 ; Ll # LATIN SMALL LETTER U WITH DIAERESIS BELOW
+1E75 ; Ll # LATIN SMALL LETTER U WITH TILDE BELOW
+1E77 ; Ll # LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+1E79 ; Ll # LATIN SMALL LETTER U WITH TILDE AND ACUTE
+1E7B ; Ll # LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+1E7D ; Ll # LATIN SMALL LETTER V WITH TILDE
+1E7F ; Ll # LATIN SMALL LETTER V WITH DOT BELOW
+1E81 ; Ll # LATIN SMALL LETTER W WITH GRAVE
+1E83 ; Ll # LATIN SMALL LETTER W WITH ACUTE
+1E85 ; Ll # LATIN SMALL LETTER W WITH DIAERESIS
+1E87 ; Ll # LATIN SMALL LETTER W WITH DOT ABOVE
+1E89 ; Ll # LATIN SMALL LETTER W WITH DOT BELOW
+1E8B ; Ll # LATIN SMALL LETTER X WITH DOT ABOVE
+1E8D ; Ll # LATIN SMALL LETTER X WITH DIAERESIS
+1E8F ; Ll # LATIN SMALL LETTER Y WITH DOT ABOVE
+1E91 ; Ll # LATIN SMALL LETTER Z WITH CIRCUMFLEX
+1E93 ; Ll # LATIN SMALL LETTER Z WITH DOT BELOW
+1E95..1E9D ; Ll # [9] LATIN SMALL LETTER Z WITH LINE BELOW..LATIN SMALL LETTER LONG S WITH HIGH STROKE
+1E9F ; Ll # LATIN SMALL LETTER DELTA
+1EA1 ; Ll # LATIN SMALL LETTER A WITH DOT BELOW
+1EA3 ; Ll # LATIN SMALL LETTER A WITH HOOK ABOVE
+1EA5 ; Ll # LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA7 ; Ll # LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA9 ; Ll # LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAB ; Ll # LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAD ; Ll # LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAF ; Ll # LATIN SMALL LETTER A WITH BREVE AND ACUTE
+1EB1 ; Ll # LATIN SMALL LETTER A WITH BREVE AND GRAVE
+1EB3 ; Ll # LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+1EB5 ; Ll # LATIN SMALL LETTER A WITH BREVE AND TILDE
+1EB7 ; Ll # LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+1EB9 ; Ll # LATIN SMALL LETTER E WITH DOT BELOW
+1EBB ; Ll # LATIN SMALL LETTER E WITH HOOK ABOVE
+1EBD ; Ll # LATIN SMALL LETTER E WITH TILDE
+1EBF ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC1 ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC3 ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC5 ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC7 ; Ll # LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC9 ; Ll # LATIN SMALL LETTER I WITH HOOK ABOVE
+1ECB ; Ll # LATIN SMALL LETTER I WITH DOT BELOW
+1ECD ; Ll # LATIN SMALL LETTER O WITH DOT BELOW
+1ECF ; Ll # LATIN SMALL LETTER O WITH HOOK ABOVE
+1ED1 ; Ll # LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED3 ; Ll # LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED5 ; Ll # LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED7 ; Ll # LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED9 ; Ll # LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDB ; Ll # LATIN SMALL LETTER O WITH HORN AND ACUTE
+1EDD ; Ll # LATIN SMALL LETTER O WITH HORN AND GRAVE
+1EDF ; Ll # LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+1EE1 ; Ll # LATIN SMALL LETTER O WITH HORN AND TILDE
+1EE3 ; Ll # LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+1EE5 ; Ll # LATIN SMALL LETTER U WITH DOT BELOW
+1EE7 ; Ll # LATIN SMALL LETTER U WITH HOOK ABOVE
+1EE9 ; Ll # LATIN SMALL LETTER U WITH HORN AND ACUTE
+1EEB ; Ll # LATIN SMALL LETTER U WITH HORN AND GRAVE
+1EED ; Ll # LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+1EEF ; Ll # LATIN SMALL LETTER U WITH HORN AND TILDE
+1EF1 ; Ll # LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+1EF3 ; Ll # LATIN SMALL LETTER Y WITH GRAVE
+1EF5 ; Ll # LATIN SMALL LETTER Y WITH DOT BELOW
+1EF7 ; Ll # LATIN SMALL LETTER Y WITH HOOK ABOVE
+1EF9 ; Ll # LATIN SMALL LETTER Y WITH TILDE
+1EFB ; Ll # LATIN SMALL LETTER MIDDLE-WELSH LL
+1EFD ; Ll # LATIN SMALL LETTER MIDDLE-WELSH V
+1EFF..1F07 ; Ll # [9] LATIN SMALL LETTER Y WITH LOOP..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F10..1F15 ; Ll # [6] GREEK SMALL LETTER EPSILON WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F27 ; Ll # [8] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
+1F30..1F37 ; Ll # [8] GREEK SMALL LETTER IOTA WITH PSILI..GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F40..1F45 ; Ll # [6] GREEK SMALL LETTER OMICRON WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Ll # [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F60..1F67 ; Ll # [8] GREEK SMALL LETTER OMEGA WITH PSILI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F70..1F7D ; Ll # [14] GREEK SMALL LETTER ALPHA WITH VARIA..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1F87 ; Ll # [8] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F90..1F97 ; Ll # [8] GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA0..1FA7 ; Ll # [8] GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FB0..1FB4 ; Ll # [5] GREEK SMALL LETTER ALPHA WITH VRACHY..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FB7 ; Ll # [2] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FBE ; Ll # GREEK PROSGEGRAMMENI
+1FC2..1FC4 ; Ll # [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FC7 ; Ll # [2] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FD0..1FD3 ; Ll # [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FD7 ; Ll # [2] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FE0..1FE7 ; Ll # [8] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FF2..1FF4 ; Ll # [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FF7 ; Ll # [2] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+2071 ; Ll # SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Ll # SUPERSCRIPT LATIN SMALL LETTER N
+210A ; Ll # SCRIPT SMALL G
+210E..210F ; Ll # [2] PLANCK CONSTANT..PLANCK CONSTANT OVER TWO PI
+2113 ; Ll # SCRIPT SMALL L
+212F ; Ll # SCRIPT SMALL E
+2134 ; Ll # SCRIPT SMALL O
+2139 ; Ll # INFORMATION SOURCE
+213C..213D ; Ll # [2] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK SMALL GAMMA
+2146..2149 ; Ll # [4] DOUBLE-STRUCK ITALIC SMALL D..DOUBLE-STRUCK ITALIC SMALL J
+214E ; Ll # TURNED SMALL F
+2184 ; Ll # LATIN SMALL LETTER REVERSED C
+2C30..2C5E ; Ll # [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+2C61 ; Ll # LATIN SMALL LETTER L WITH DOUBLE BAR
+2C65..2C66 ; Ll # [2] LATIN SMALL LETTER A WITH STROKE..LATIN SMALL LETTER T WITH DIAGONAL STROKE
+2C68 ; Ll # LATIN SMALL LETTER H WITH DESCENDER
+2C6A ; Ll # LATIN SMALL LETTER K WITH DESCENDER
+2C6C ; Ll # LATIN SMALL LETTER Z WITH DESCENDER
+2C71 ; Ll # LATIN SMALL LETTER V WITH RIGHT HOOK
+2C73..2C74 ; Ll # [2] LATIN SMALL LETTER W WITH HOOK..LATIN SMALL LETTER V WITH CURL
+2C76..2C7C ; Ll # [7] LATIN SMALL LETTER HALF H..LATIN SUBSCRIPT SMALL LETTER J
+2C81 ; Ll # COPTIC SMALL LETTER ALFA
+2C83 ; Ll # COPTIC SMALL LETTER VIDA
+2C85 ; Ll # COPTIC SMALL LETTER GAMMA
+2C87 ; Ll # COPTIC SMALL LETTER DALDA
+2C89 ; Ll # COPTIC SMALL LETTER EIE
+2C8B ; Ll # COPTIC SMALL LETTER SOU
+2C8D ; Ll # COPTIC SMALL LETTER ZATA
+2C8F ; Ll # COPTIC SMALL LETTER HATE
+2C91 ; Ll # COPTIC SMALL LETTER THETHE
+2C93 ; Ll # COPTIC SMALL LETTER IAUDA
+2C95 ; Ll # COPTIC SMALL LETTER KAPA
+2C97 ; Ll # COPTIC SMALL LETTER LAULA
+2C99 ; Ll # COPTIC SMALL LETTER MI
+2C9B ; Ll # COPTIC SMALL LETTER NI
+2C9D ; Ll # COPTIC SMALL LETTER KSI
+2C9F ; Ll # COPTIC SMALL LETTER O
+2CA1 ; Ll # COPTIC SMALL LETTER PI
+2CA3 ; Ll # COPTIC SMALL LETTER RO
+2CA5 ; Ll # COPTIC SMALL LETTER SIMA
+2CA7 ; Ll # COPTIC SMALL LETTER TAU
+2CA9 ; Ll # COPTIC SMALL LETTER UA
+2CAB ; Ll # COPTIC SMALL LETTER FI
+2CAD ; Ll # COPTIC SMALL LETTER KHI
+2CAF ; Ll # COPTIC SMALL LETTER PSI
+2CB1 ; Ll # COPTIC SMALL LETTER OOU
+2CB3 ; Ll # COPTIC SMALL LETTER DIALECT-P ALEF
+2CB5 ; Ll # COPTIC SMALL LETTER OLD COPTIC AIN
+2CB7 ; Ll # COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
+2CB9 ; Ll # COPTIC SMALL LETTER DIALECT-P KAPA
+2CBB ; Ll # COPTIC SMALL LETTER DIALECT-P NI
+2CBD ; Ll # COPTIC SMALL LETTER CRYPTOGRAMMIC NI
+2CBF ; Ll # COPTIC SMALL LETTER OLD COPTIC OOU
+2CC1 ; Ll # COPTIC SMALL LETTER SAMPI
+2CC3 ; Ll # COPTIC SMALL LETTER CROSSED SHEI
+2CC5 ; Ll # COPTIC SMALL LETTER OLD COPTIC SHEI
+2CC7 ; Ll # COPTIC SMALL LETTER OLD COPTIC ESH
+2CC9 ; Ll # COPTIC SMALL LETTER AKHMIMIC KHEI
+2CCB ; Ll # COPTIC SMALL LETTER DIALECT-P HORI
+2CCD ; Ll # COPTIC SMALL LETTER OLD COPTIC HORI
+2CCF ; Ll # COPTIC SMALL LETTER OLD COPTIC HA
+2CD1 ; Ll # COPTIC SMALL LETTER L-SHAPED HA
+2CD3 ; Ll # COPTIC SMALL LETTER OLD COPTIC HEI
+2CD5 ; Ll # COPTIC SMALL LETTER OLD COPTIC HAT
+2CD7 ; Ll # COPTIC SMALL LETTER OLD COPTIC GANGIA
+2CD9 ; Ll # COPTIC SMALL LETTER OLD COPTIC DJA
+2CDB ; Ll # COPTIC SMALL LETTER OLD COPTIC SHIMA
+2CDD ; Ll # COPTIC SMALL LETTER OLD NUBIAN SHIMA
+2CDF ; Ll # COPTIC SMALL LETTER OLD NUBIAN NGI
+2CE1 ; Ll # COPTIC SMALL LETTER OLD NUBIAN NYI
+2CE3..2CE4 ; Ll # [2] COPTIC SMALL LETTER OLD NUBIAN WAU..COPTIC SYMBOL KAI
+2D00..2D25 ; Ll # [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+A641 ; Ll # CYRILLIC SMALL LETTER ZEMLYA
+A643 ; Ll # CYRILLIC SMALL LETTER DZELO
+A645 ; Ll # CYRILLIC SMALL LETTER REVERSED DZE
+A647 ; Ll # CYRILLIC SMALL LETTER IOTA
+A649 ; Ll # CYRILLIC SMALL LETTER DJERV
+A64B ; Ll # CYRILLIC SMALL LETTER MONOGRAPH UK
+A64D ; Ll # CYRILLIC SMALL LETTER BROAD OMEGA
+A64F ; Ll # CYRILLIC SMALL LETTER NEUTRAL YER
+A651 ; Ll # CYRILLIC SMALL LETTER YERU WITH BACK YER
+A653 ; Ll # CYRILLIC SMALL LETTER IOTIFIED YAT
+A655 ; Ll # CYRILLIC SMALL LETTER REVERSED YU
+A657 ; Ll # CYRILLIC SMALL LETTER IOTIFIED A
+A659 ; Ll # CYRILLIC SMALL LETTER CLOSED LITTLE YUS
+A65B ; Ll # CYRILLIC SMALL LETTER BLENDED YUS
+A65D ; Ll # CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS
+A65F ; Ll # CYRILLIC SMALL LETTER YN
+A663 ; Ll # CYRILLIC SMALL LETTER SOFT DE
+A665 ; Ll # CYRILLIC SMALL LETTER SOFT EL
+A667 ; Ll # CYRILLIC SMALL LETTER SOFT EM
+A669 ; Ll # CYRILLIC SMALL LETTER MONOCULAR O
+A66B ; Ll # CYRILLIC SMALL LETTER BINOCULAR O
+A66D ; Ll # CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A681 ; Ll # CYRILLIC SMALL LETTER DWE
+A683 ; Ll # CYRILLIC SMALL LETTER DZWE
+A685 ; Ll # CYRILLIC SMALL LETTER ZHWE
+A687 ; Ll # CYRILLIC SMALL LETTER CCHE
+A689 ; Ll # CYRILLIC SMALL LETTER DZZE
+A68B ; Ll # CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK
+A68D ; Ll # CYRILLIC SMALL LETTER TWE
+A68F ; Ll # CYRILLIC SMALL LETTER TSWE
+A691 ; Ll # CYRILLIC SMALL LETTER TSSE
+A693 ; Ll # CYRILLIC SMALL LETTER TCHE
+A695 ; Ll # CYRILLIC SMALL LETTER HWE
+A697 ; Ll # CYRILLIC SMALL LETTER SHWE
+A723 ; Ll # LATIN SMALL LETTER EGYPTOLOGICAL ALEF
+A725 ; Ll # LATIN SMALL LETTER EGYPTOLOGICAL AIN
+A727 ; Ll # LATIN SMALL LETTER HENG
+A729 ; Ll # LATIN SMALL LETTER TZ
+A72B ; Ll # LATIN SMALL LETTER TRESILLO
+A72D ; Ll # LATIN SMALL LETTER CUATRILLO
+A72F..A731 ; Ll # [3] LATIN SMALL LETTER CUATRILLO WITH COMMA..LATIN LETTER SMALL CAPITAL S
+A733 ; Ll # LATIN SMALL LETTER AA
+A735 ; Ll # LATIN SMALL LETTER AO
+A737 ; Ll # LATIN SMALL LETTER AU
+A739 ; Ll # LATIN SMALL LETTER AV
+A73B ; Ll # LATIN SMALL LETTER AV WITH HORIZONTAL BAR
+A73D ; Ll # LATIN SMALL LETTER AY
+A73F ; Ll # LATIN SMALL LETTER REVERSED C WITH DOT
+A741 ; Ll # LATIN SMALL LETTER K WITH STROKE
+A743 ; Ll # LATIN SMALL LETTER K WITH DIAGONAL STROKE
+A745 ; Ll # LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE
+A747 ; Ll # LATIN SMALL LETTER BROKEN L
+A749 ; Ll # LATIN SMALL LETTER L WITH HIGH STROKE
+A74B ; Ll # LATIN SMALL LETTER O WITH LONG STROKE OVERLAY
+A74D ; Ll # LATIN SMALL LETTER O WITH LOOP
+A74F ; Ll # LATIN SMALL LETTER OO
+A751 ; Ll # LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER
+A753 ; Ll # LATIN SMALL LETTER P WITH FLOURISH
+A755 ; Ll # LATIN SMALL LETTER P WITH SQUIRREL TAIL
+A757 ; Ll # LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER
+A759 ; Ll # LATIN SMALL LETTER Q WITH DIAGONAL STROKE
+A75B ; Ll # LATIN SMALL LETTER R ROTUNDA
+A75D ; Ll # LATIN SMALL LETTER RUM ROTUNDA
+A75F ; Ll # LATIN SMALL LETTER V WITH DIAGONAL STROKE
+A761 ; Ll # LATIN SMALL LETTER VY
+A763 ; Ll # LATIN SMALL LETTER VISIGOTHIC Z
+A765 ; Ll # LATIN SMALL LETTER THORN WITH STROKE
+A767 ; Ll # LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER
+A769 ; Ll # LATIN SMALL LETTER VEND
+A76B ; Ll # LATIN SMALL LETTER ET
+A76D ; Ll # LATIN SMALL LETTER IS
+A76F ; Ll # LATIN SMALL LETTER CON
+A771..A778 ; Ll # [8] LATIN SMALL LETTER DUM..LATIN SMALL LETTER UM
+A77A ; Ll # LATIN SMALL LETTER INSULAR D
+A77C ; Ll # LATIN SMALL LETTER INSULAR F
+A77F ; Ll # LATIN SMALL LETTER TURNED INSULAR G
+A781 ; Ll # LATIN SMALL LETTER TURNED L
+A783 ; Ll # LATIN SMALL LETTER INSULAR R
+A785 ; Ll # LATIN SMALL LETTER INSULAR S
+A787 ; Ll # LATIN SMALL LETTER INSULAR T
+A78C ; Ll # LATIN SMALL LETTER SALTILLO
+FB00..FB06 ; Ll # [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FB13..FB17 ; Ll # [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+FF41..FF5A ; Ll # [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+10428..1044F ; Ll # [40] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER EW
+1D41A..1D433 ; Ll # [26] MATHEMATICAL BOLD SMALL A..MATHEMATICAL BOLD SMALL Z
+1D44E..1D454 ; Ll # [7] MATHEMATICAL ITALIC SMALL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D467 ; Ll # [18] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL ITALIC SMALL Z
+1D482..1D49B ; Ll # [26] MATHEMATICAL BOLD ITALIC SMALL A..MATHEMATICAL BOLD ITALIC SMALL Z
+1D4B6..1D4B9 ; Ll # [4] MATHEMATICAL SCRIPT SMALL A..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Ll # MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Ll # [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D4CF ; Ll # [11] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL SCRIPT SMALL Z
+1D4EA..1D503 ; Ll # [26] MATHEMATICAL BOLD SCRIPT SMALL A..MATHEMATICAL BOLD SCRIPT SMALL Z
+1D51E..1D537 ; Ll # [26] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL FRAKTUR SMALL Z
+1D552..1D56B ; Ll # [26] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL DOUBLE-STRUCK SMALL Z
+1D586..1D59F ; Ll # [26] MATHEMATICAL BOLD FRAKTUR SMALL A..MATHEMATICAL BOLD FRAKTUR SMALL Z
+1D5BA..1D5D3 ; Ll # [26] MATHEMATICAL SANS-SERIF SMALL A..MATHEMATICAL SANS-SERIF SMALL Z
+1D5EE..1D607 ; Ll # [26] MATHEMATICAL SANS-SERIF BOLD SMALL A..MATHEMATICAL SANS-SERIF BOLD SMALL Z
+1D622..1D63B ; Ll # [26] MATHEMATICAL SANS-SERIF ITALIC SMALL A..MATHEMATICAL SANS-SERIF ITALIC SMALL Z
+1D656..1D66F ; Ll # [26] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z
+1D68A..1D6A5 ; Ll # [28] MATHEMATICAL MONOSPACE SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6C2..1D6DA ; Ll # [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DC..1D6E1 ; Ll # [6] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL BOLD PI SYMBOL
+1D6FC..1D714 ; Ll # [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D716..1D71B ; Ll # [6] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL ITALIC PI SYMBOL
+1D736..1D74E ; Ll # [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D750..1D755 ; Ll # [6] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC PI SYMBOL
+1D770..1D788 ; Ll # [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D78A..1D78F ; Ll # [6] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD PI SYMBOL
+1D7AA..1D7C2 ; Ll # [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C4..1D7C9 ; Ll # [6] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL
+1D7CB ; Ll # MATHEMATICAL BOLD SMALL DIGAMMA
+
+# Total code points: 1748
+
+# ================================================
+
+# General_Category=Titlecase_Letter
+
+01C5 ; Lt # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C8 ; Lt # LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CB ; Lt # LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01F2 ; Lt # LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+1F88..1F8F ; Lt # [8] GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F98..1F9F ; Lt # [8] GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FA8..1FAF ; Lt # [8] GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI..GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FBC ; Lt # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FCC ; Lt # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FFC ; Lt # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+
+# Total code points: 31
+
+# ================================================
+
+# General_Category=Modifier_Letter
+
+02B0..02C1 ; Lm # [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C6..02D1 ; Lm # [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02E0..02E4 ; Lm # [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+02EC ; Lm # MODIFIER LETTER VOICING
+02EE ; Lm # MODIFIER LETTER DOUBLE APOSTROPHE
+0374 ; Lm # GREEK NUMERAL SIGN
+037A ; Lm # GREEK YPOGEGRAMMENI
+0559 ; Lm # ARMENIAN MODIFIER LETTER LEFT HALF RING
+0640 ; Lm # ARABIC TATWEEL
+06E5..06E6 ; Lm # [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+07F4..07F5 ; Lm # [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07FA ; Lm # NKO LAJANYALAN
+0971 ; Lm # DEVANAGARI SIGN HIGH SPACING DOT
+0E46 ; Lm # THAI CHARACTER MAIYAMOK
+0EC6 ; Lm # LAO KO LA
+10FC ; Lm # MODIFIER LETTER GEORGIAN NAR
+17D7 ; Lm # KHMER SIGN LEK TOO
+1843 ; Lm # MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1C78..1C7D ; Lm # [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1D2C..1D61 ; Lm # [54] MODIFIER LETTER CAPITAL A..MODIFIER LETTER SMALL CHI
+1D78 ; Lm # MODIFIER LETTER CYRILLIC EN
+1D9B..1DBF ; Lm # [37] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL THETA
+2090..2094 ; Lm # [5] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER SCHWA
+2C7D ; Lm # MODIFIER LETTER CAPITAL V
+2D6F ; Lm # TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+2E2F ; Lm # VERTICAL TILDE
+3005 ; Lm # IDEOGRAPHIC ITERATION MARK
+3031..3035 ; Lm # [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+303B ; Lm # VERTICAL IDEOGRAPHIC ITERATION MARK
+309D..309E ; Lm # [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+30FC..30FE ; Lm # [3] KATAKANA-HIRAGANA PROLONGED SOUND MARK..KATAKANA VOICED ITERATION MARK
+A015 ; Lm # YI SYLLABLE WU
+A60C ; Lm # VAI SYLLABLE LENGTHENER
+A67F ; Lm # CYRILLIC PAYEROK
+A717..A71F ; Lm # [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A770 ; Lm # MODIFIER LETTER US
+A788 ; Lm # MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+FF70 ; Lm # HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF9E..FF9F ; Lm # [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+
+# Total code points: 187
+
+# ================================================
+
+# General_Category=Other_Letter
+
+01BB ; Lo # LATIN LETTER TWO WITH STROKE
+01C0..01C3 ; Lo # [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+0294 ; Lo # LATIN LETTER GLOTTAL STOP
+05D0..05EA ; Lo # [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; Lo # [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+0621..063F ; Lo # [31] ARABIC LETTER HAMZA..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0641..064A ; Lo # [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+066E..066F ; Lo # [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; Lo # [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D5 ; Lo # ARABIC LETTER AE
+06EE..06EF ; Lo # [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06FA..06FC ; Lo # [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FF ; Lo # ARABIC LETTER HEH WITH INVERTED V
+0710 ; Lo # SYRIAC LETTER ALAPH
+0712..072F ; Lo # [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+074D..07A5 ; Lo # [89] SYRIAC LETTER SOGDIAN ZHAIN..THAANA LETTER WAAVU
+07B1 ; Lo # THAANA LETTER NAA
+07CA..07EA ; Lo # [33] NKO LETTER A..NKO LETTER JONA RA
+0904..0939 ; Lo # [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093D ; Lo # DEVANAGARI SIGN AVAGRAHA
+0950 ; Lo # DEVANAGARI OM
+0958..0961 ; Lo # [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0972 ; Lo # DEVANAGARI LETTER CANDRA A
+097B..097F ; Lo # [5] DEVANAGARI LETTER GGA..DEVANAGARI LETTER BBA
+0985..098C ; Lo # [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; Lo # [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; Lo # [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; Lo # [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; Lo # BENGALI LETTER LA
+09B6..09B9 ; Lo # [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BD ; Lo # BENGALI SIGN AVAGRAHA
+09CE ; Lo # BENGALI LETTER KHANDA TA
+09DC..09DD ; Lo # [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; Lo # [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09F0..09F1 ; Lo # [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+0A05..0A0A ; Lo # [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; Lo # [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; Lo # [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; Lo # [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; Lo # [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; Lo # [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; Lo # [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A59..0A5C ; Lo # [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; Lo # GURMUKHI LETTER FA
+0A72..0A74 ; Lo # [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A85..0A8D ; Lo # [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; Lo # [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; Lo # [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; Lo # [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; Lo # [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; Lo # [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABD ; Lo # GUJARATI SIGN AVAGRAHA
+0AD0 ; Lo # GUJARATI OM
+0AE0..0AE1 ; Lo # [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0B05..0B0C ; Lo # [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; Lo # [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; Lo # [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; Lo # [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; Lo # [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; Lo # [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3D ; Lo # ORIYA SIGN AVAGRAHA
+0B5C..0B5D ; Lo # [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; Lo # [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B71 ; Lo # ORIYA LETTER WA
+0B83 ; Lo # TAMIL SIGN VISARGA
+0B85..0B8A ; Lo # [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; Lo # [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; Lo # [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; Lo # [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; Lo # TAMIL LETTER JA
+0B9E..0B9F ; Lo # [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; Lo # [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; Lo # [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; Lo # [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BD0 ; Lo # TAMIL OM
+0C05..0C0C ; Lo # [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; Lo # [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; Lo # [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C33 ; Lo # [10] TELUGU LETTER PA..TELUGU LETTER LLA
+0C35..0C39 ; Lo # [5] TELUGU LETTER VA..TELUGU LETTER HA
+0C3D ; Lo # TELUGU SIGN AVAGRAHA
+0C58..0C59 ; Lo # [2] TELUGU LETTER TSA..TELUGU LETTER DZA
+0C60..0C61 ; Lo # [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C85..0C8C ; Lo # [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; Lo # [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; Lo # [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; Lo # [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; Lo # [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBD ; Lo # KANNADA SIGN AVAGRAHA
+0CDE ; Lo # KANNADA LETTER FA
+0CE0..0CE1 ; Lo # [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0D05..0D0C ; Lo # [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; Lo # [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D28 ; Lo # [23] MALAYALAM LETTER O..MALAYALAM LETTER NA
+0D2A..0D39 ; Lo # [16] MALAYALAM LETTER PA..MALAYALAM LETTER HA
+0D3D ; Lo # MALAYALAM SIGN AVAGRAHA
+0D60..0D61 ; Lo # [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL
+0D7A..0D7F ; Lo # [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+0D85..0D96 ; Lo # [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; Lo # [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; Lo # [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; Lo # SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; Lo # [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0E01..0E30 ; Lo # [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E32..0E33 ; Lo # [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E40..0E45 ; Lo # [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E81..0E82 ; Lo # [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; Lo # LAO LETTER KHO TAM
+0E87..0E88 ; Lo # [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; Lo # LAO LETTER SO TAM
+0E8D ; Lo # LAO LETTER NYO
+0E94..0E97 ; Lo # [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; Lo # [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; Lo # [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; Lo # LAO LETTER LO LOOT
+0EA7 ; Lo # LAO LETTER WO
+0EAA..0EAB ; Lo # [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; Lo # [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB2..0EB3 ; Lo # [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EBD ; Lo # LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; Lo # [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EDC..0EDD ; Lo # [2] LAO HO NO..LAO HO MO
+0F00 ; Lo # TIBETAN SYLLABLE OM
+0F40..0F47 ; Lo # [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; Lo # [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F88..0F8B ; Lo # [4] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN GRU MED RGYINGS
+1000..102A ; Lo # [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+103F ; Lo # MYANMAR LETTER GREAT SA
+1050..1055 ; Lo # [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+105A..105D ; Lo # [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+1061 ; Lo # MYANMAR LETTER SGAW KAREN SHA
+1065..1066 ; Lo # [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+106E..1070 ; Lo # [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1075..1081 ; Lo # [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+108E ; Lo # MYANMAR LETTER RUMAI PALAUNG FA
+10D0..10FA ; Lo # [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+1100..1159 ; Lo # [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH
+115F..11A2 ; Lo # [68] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG SSANGARAEA
+11A8..11F9 ; Lo # [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH
+1200..1248 ; Lo # [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+124A..124D ; Lo # [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; Lo # [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; Lo # ETHIOPIC SYLLABLE QHWA
+125A..125D ; Lo # [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; Lo # [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; Lo # [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; Lo # [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; Lo # [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; Lo # [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; Lo # ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; Lo # [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; Lo # [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; Lo # [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; Lo # [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; Lo # [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+1380..138F ; Lo # [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+13A0..13F4 ; Lo # [85] CHEROKEE LETTER A..CHEROKEE LETTER YV
+1401..166C ; Lo # [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166F..1676 ; Lo # [8] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA
+1681..169A ; Lo # [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+16A0..16EA ; Lo # [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+1700..170C ; Lo # [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; Lo # [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1720..1731 ; Lo # [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1740..1751 ; Lo # [18] BUHID LETTER A..BUHID LETTER HA
+1760..176C ; Lo # [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; Lo # [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1780..17B3 ; Lo # [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17DC ; Lo # KHMER SIGN AVAKRAHASANYA
+1820..1842 ; Lo # [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1844..1877 ; Lo # [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..18A8 ; Lo # [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18AA ; Lo # MONGOLIAN LETTER MANCHU ALI GALI LHA
+1900..191C ; Lo # [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA
+1950..196D ; Lo # [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; Lo # [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+1980..19A9 ; Lo # [42] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW XVA
+19C1..19C7 ; Lo # [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B
+1A00..1A16 ; Lo # [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1B05..1B33 ; Lo # [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B45..1B4B ; Lo # [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B83..1BA0 ; Lo # [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BAE..1BAF ; Lo # [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1C00..1C23 ; Lo # [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C4D..1C4F ; Lo # [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+1C5A..1C77 ; Lo # [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+2135..2138 ; Lo # [4] ALEF SYMBOL..DALET SYMBOL
+2D30..2D65 ; Lo # [54] TIFINAGH LETTER YA..TIFINAGH LETTER YAZZ
+2D80..2D96 ; Lo # [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; Lo # [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; Lo # [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; Lo # [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; Lo # [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; Lo # [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; Lo # [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; Lo # [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; Lo # [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+3006 ; Lo # IDEOGRAPHIC CLOSING MARK
+303C ; Lo # MASU MARK
+3041..3096 ; Lo # [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309F ; Lo # HIRAGANA DIGRAPH YORI
+30A1..30FA ; Lo # [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FF ; Lo # KATAKANA DIGRAPH KOTO
+3105..312D ; Lo # [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+3131..318E ; Lo # [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+31A0..31B7 ; Lo # [24] BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H
+31F0..31FF ; Lo # [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+3400..4DB5 ; Lo # [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FC3 ; Lo # [20932] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FC3
+A000..A014 ; Lo # [21] YI SYLLABLE IT..YI SYLLABLE E
+A016..A48C ; Lo # [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A500..A60B ; Lo # [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A610..A61F ; Lo # [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A62A..A62B ; Lo # [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+A66E ; Lo # CYRILLIC LETTER MULTIOCULAR O
+A7FB..A801 ; Lo # [7] LATIN EPIGRAPHIC LETTER REVERSED F..SYLOTI NAGRI LETTER I
+A803..A805 ; Lo # [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A807..A80A ; Lo # [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80C..A822 ; Lo # [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A840..A873 ; Lo # [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A882..A8B3 ; Lo # [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A90A..A925 ; Lo # [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A930..A946 ; Lo # [23] REJANG LETTER KA..REJANG LETTER A
+AA00..AA28 ; Lo # [41] CHAM LETTER A..CHAM LETTER HA
+AA40..AA42 ; Lo # [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA44..AA4B ; Lo # [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AC00..D7A3 ; Lo # [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+F900..FA2D ; Lo # [302] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA2D
+FA30..FA6A ; Lo # [59] CJK COMPATIBILITY IDEOGRAPH-FA30..CJK COMPATIBILITY IDEOGRAPH-FA6A
+FA70..FAD9 ; Lo # [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+FB1D ; Lo # HEBREW LETTER YOD WITH HIRIQ
+FB1F..FB28 ; Lo # [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB2A..FB36 ; Lo # [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; Lo # [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; Lo # HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; Lo # [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; Lo # [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FBB1 ; Lo # [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; Lo # [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; Lo # [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; Lo # [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; Lo # [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FE70..FE74 ; Lo # [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; Lo # [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+FF66..FF6F ; Lo # [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF71..FF9D ; Lo # [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+FFA0..FFBE ; Lo # [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; Lo # [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; Lo # [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; Lo # [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; Lo # [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+10000..1000B ; Lo # [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; Lo # [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; Lo # [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; Lo # [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; Lo # [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; Lo # [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; Lo # [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+10280..1029C ; Lo # [29] LYCIAN LETTER A..LYCIAN LETTER X
+102A0..102D0 ; Lo # [49] CARIAN LETTER A..CARIAN LETTER UUU3
+10300..1031E ; Lo # [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU
+10330..10340 ; Lo # [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10342..10349 ; Lo # [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+10380..1039D ; Lo # [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+103A0..103C3 ; Lo # [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; Lo # [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+10450..1049D ; Lo # [78] SHAVIAN LETTER PEEP..OSMANYA LETTER OO
+10800..10805 ; Lo # [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; Lo # CYPRIOT SYLLABLE JO
+1080A..10835 ; Lo # [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; Lo # [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; Lo # CYPRIOT SYLLABLE ZA
+1083F ; Lo # CYPRIOT SYLLABLE ZO
+10900..10915 ; Lo # [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10920..10939 ; Lo # [26] LYDIAN LETTER A..LYDIAN LETTER C
+10A00 ; Lo # KHAROSHTHI LETTER A
+10A10..10A13 ; Lo # [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; Lo # [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; Lo # [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+12000..1236E ; Lo # [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM
+20000..2A6D6 ; Lo # [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2F800..2FA1D ; Lo # [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 90068
+
+# ================================================
+
+# General_Category=Nonspacing_Mark
+
+0300..036F ; Mn # [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0483..0487 ; Mn # [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0591..05BD ; Mn # [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; Mn # HEBREW POINT RAFE
+05C1..05C2 ; Mn # [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Mn # [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Mn # HEBREW POINT QAMATS QATAN
+0610..061A ; Mn # [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+064B..065E ; Mn # [20] ARABIC FATHATAN..ARABIC FATHA WITH TWO DOTS
+0670 ; Mn # ARABIC LETTER SUPERSCRIPT ALEF
+06D6..06DC ; Mn # [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DF..06E4 ; Mn # [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E7..06E8 ; Mn # [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; Mn # [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+0711 ; Mn # SYRIAC LETTER SUPERSCRIPT ALAPH
+0730..074A ; Mn # [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+07A6..07B0 ; Mn # [11] THAANA ABAFILI..THAANA SUKUN
+07EB..07F3 ; Mn # [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+0901..0902 ; Mn # [2] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+093C ; Mn # DEVANAGARI SIGN NUKTA
+0941..0948 ; Mn # [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+094D ; Mn # DEVANAGARI SIGN VIRAMA
+0951..0954 ; Mn # [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT
+0962..0963 ; Mn # [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0981 ; Mn # BENGALI SIGN CANDRABINDU
+09BC ; Mn # BENGALI SIGN NUKTA
+09C1..09C4 ; Mn # [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09CD ; Mn # BENGALI SIGN VIRAMA
+09E2..09E3 ; Mn # [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+0A01..0A02 ; Mn # [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A3C ; Mn # GURMUKHI SIGN NUKTA
+0A41..0A42 ; Mn # [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Mn # [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Mn # [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Mn # GURMUKHI SIGN UDAAT
+0A70..0A71 ; Mn # [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A75 ; Mn # GURMUKHI SIGN YAKASH
+0A81..0A82 ; Mn # [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0ABC ; Mn # GUJARATI SIGN NUKTA
+0AC1..0AC5 ; Mn # [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Mn # [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0ACD ; Mn # GUJARATI SIGN VIRAMA
+0AE2..0AE3 ; Mn # [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0B01 ; Mn # ORIYA SIGN CANDRABINDU
+0B3C ; Mn # ORIYA SIGN NUKTA
+0B3F ; Mn # ORIYA VOWEL SIGN I
+0B41..0B44 ; Mn # [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B4D ; Mn # ORIYA SIGN VIRAMA
+0B56 ; Mn # ORIYA AI LENGTH MARK
+0B62..0B63 ; Mn # [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B82 ; Mn # TAMIL SIGN ANUSVARA
+0BC0 ; Mn # TAMIL VOWEL SIGN II
+0BCD ; Mn # TAMIL SIGN VIRAMA
+0C3E..0C40 ; Mn # [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C46..0C48 ; Mn # [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Mn # [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Mn # [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C62..0C63 ; Mn # [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0CBC ; Mn # KANNADA SIGN NUKTA
+0CBF ; Mn # KANNADA VOWEL SIGN I
+0CC6 ; Mn # KANNADA VOWEL SIGN E
+0CCC..0CCD ; Mn # [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CE2..0CE3 ; Mn # [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0D41..0D44 ; Mn # [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D4D ; Mn # MALAYALAM SIGN VIRAMA
+0D62..0D63 ; Mn # [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0DCA ; Mn # SINHALA SIGN AL-LAKUNA
+0DD2..0DD4 ; Mn # [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Mn # SINHALA VOWEL SIGN DIGA PAA-PILLA
+0E31 ; Mn # THAI CHARACTER MAI HAN-AKAT
+0E34..0E3A ; Mn # [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E47..0E4E ; Mn # [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0EB1 ; Mn # LAO VOWEL SIGN MAI KAN
+0EB4..0EB9 ; Mn # [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Mn # [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EC8..0ECD ; Mn # [6] LAO TONE MAI EK..LAO NIGGAHITA
+0F18..0F19 ; Mn # [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; Mn # TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; Mn # TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; Mn # TIBETAN MARK TSA -PHRU
+0F71..0F7E ; Mn # [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F80..0F84 ; Mn # [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; Mn # [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F90..0F97 ; Mn # [8] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Mn # [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; Mn # TIBETAN SYMBOL PADMA GDAN
+102D..1030 ; Mn # [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1032..1037 ; Mn # [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1039..103A ; Mn # [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103D..103E ; Mn # [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+1058..1059 ; Mn # [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105E..1060 ; Mn # [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1071..1074 ; Mn # [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1082 ; Mn # MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1085..1086 ; Mn # [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+108D ; Mn # MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+135F ; Mn # ETHIOPIC COMBINING GEMINATION MARK
+1712..1714 ; Mn # [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1732..1734 ; Mn # [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1752..1753 ; Mn # [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1772..1773 ; Mn # [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+17B7..17BD ; Mn # [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17C6 ; Mn # KHMER SIGN NIKAHIT
+17C9..17D3 ; Mn # [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17DD ; Mn # KHMER SIGN ATTHACAN
+180B..180D ; Mn # [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+18A9 ; Mn # MONGOLIAN LETTER ALI GALI DAGALGA
+1920..1922 ; Mn # [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1927..1928 ; Mn # [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1932 ; Mn # LIMBU SMALL LETTER ANUSVARA
+1939..193B ; Mn # [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1A17..1A18 ; Mn # [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1B00..1B03 ; Mn # [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B34 ; Mn # BALINESE SIGN REREKAN
+1B36..1B3A ; Mn # [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3C ; Mn # BALINESE VOWEL SIGN LA LENGA
+1B42 ; Mn # BALINESE VOWEL SIGN PEPET
+1B6B..1B73 ; Mn # [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; Mn # [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1BA2..1BA5 ; Mn # [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA8..1BA9 ; Mn # [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1C2C..1C33 ; Mn # [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C36..1C37 ; Mn # [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1DC0..1DE6 ; Mn # [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z
+1DFE..1DFF ; Mn # [2] COMBINING LEFT ARROWHEAD ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+20D0..20DC ; Mn # [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20E1 ; Mn # COMBINING LEFT RIGHT ARROW ABOVE
+20E5..20F0 ; Mn # [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2DE0..2DFF ; Mn # [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+302A..302F ; Mn # [6] IDEOGRAPHIC LEVEL TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3099..309A ; Mn # [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+A66F ; Mn # COMBINING CYRILLIC VZMET
+A67C..A67D ; Mn # [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
+A802 ; Mn # SYLOTI NAGRI SIGN DVISVARA
+A806 ; Mn # SYLOTI NAGRI SIGN HASANTA
+A80B ; Mn # SYLOTI NAGRI SIGN ANUSVARA
+A825..A826 ; Mn # [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A8C4 ; Mn # SAURASHTRA SIGN VIRAMA
+A926..A92D ; Mn # [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A947..A951 ; Mn # [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+AA29..AA2E ; Mn # [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA31..AA32 ; Mn # [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA35..AA36 ; Mn # [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA43 ; Mn # CHAM CONSONANT SIGN FINAL NG
+AA4C ; Mn # CHAM CONSONANT SIGN FINAL M
+FB1E ; Mn # HEBREW POINT JUDEO-SPANISH VARIKA
+FE00..FE0F ; Mn # [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE26 ; Mn # [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
+101FD ; Mn # PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+10A01..10A03 ; Mn # [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Mn # [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Mn # [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A38..10A3A ; Mn # [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Mn # KHAROSHTHI VIRAMA
+1D167..1D169 ; Mn # [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D17B..1D182 ; Mn # [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Mn # [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Mn # [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; Mn # [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+E0100..E01EF ; Mn # [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 1032
+
+# ================================================
+
+# General_Category=Enclosing_Mark
+
+0488..0489 ; Me # [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+06DE ; Me # ARABIC START OF RUB EL HIZB
+20DD..20E0 ; Me # [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E2..20E4 ; Me # [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+A670..A672 ; Me # [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+
+# Total code points: 13
+
+# ================================================
+
+# General_Category=Spacing_Mark
+
+0903 ; Mc # DEVANAGARI SIGN VISARGA
+093E..0940 ; Mc # [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0949..094C ; Mc # [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+0982..0983 ; Mc # [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+09BE..09C0 ; Mc # [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C7..09C8 ; Mc # [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; Mc # [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09D7 ; Mc # BENGALI AU LENGTH MARK
+0A03 ; Mc # GURMUKHI SIGN VISARGA
+0A3E..0A40 ; Mc # [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A83 ; Mc # GUJARATI SIGN VISARGA
+0ABE..0AC0 ; Mc # [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC9 ; Mc # GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; Mc # [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0B02..0B03 ; Mc # [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B3E ; Mc # ORIYA VOWEL SIGN AA
+0B40 ; Mc # ORIYA VOWEL SIGN II
+0B47..0B48 ; Mc # [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; Mc # [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B57 ; Mc # ORIYA AU LENGTH MARK
+0BBE..0BBF ; Mc # [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC1..0BC2 ; Mc # [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; Mc # [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; Mc # [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BD7 ; Mc # TAMIL AU LENGTH MARK
+0C01..0C03 ; Mc # [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C41..0C44 ; Mc # [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C82..0C83 ; Mc # [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0CBE ; Mc # KANNADA VOWEL SIGN AA
+0CC0..0CC4 ; Mc # [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC7..0CC8 ; Mc # [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; Mc # [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CD5..0CD6 ; Mc # [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0D02..0D03 ; Mc # [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D3E..0D40 ; Mc # [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D46..0D48 ; Mc # [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; Mc # [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D57 ; Mc # MALAYALAM AU LENGTH MARK
+0D82..0D83 ; Mc # [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0DCF..0DD1 ; Mc # [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD8..0DDF ; Mc # [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DF2..0DF3 ; Mc # [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0F3E..0F3F ; Mc # [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F7F ; Mc # TIBETAN SIGN RNAM BCAD
+102B..102C ; Mc # [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+1031 ; Mc # MYANMAR VOWEL SIGN E
+1038 ; Mc # MYANMAR SIGN VISARGA
+103B..103C ; Mc # [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+1056..1057 ; Mc # [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1062..1064 ; Mc # [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1067..106D ; Mc # [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+1083..1084 ; Mc # [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1087..108C ; Mc # [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108F ; Mc # MYANMAR SIGN RUMAI PALAUNG TONE-5
+17B6 ; Mc # KHMER VOWEL SIGN AA
+17BE..17C5 ; Mc # [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C7..17C8 ; Mc # [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+1923..1926 ; Mc # [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1929..192B ; Mc # [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; Mc # [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1933..1938 ; Mc # [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+19B0..19C0 ; Mc # [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY
+19C8..19C9 ; Mc # [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2
+1A19..1A1B ; Mc # [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
+1B04 ; Mc # BALINESE SIGN BISAH
+1B35 ; Mc # BALINESE VOWEL SIGN TEDUNG
+1B3B ; Mc # BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3D..1B41 ; Mc # [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B43..1B44 ; Mc # [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B82 ; Mc # SUNDANESE SIGN PANGWISAD
+1BA1 ; Mc # SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA6..1BA7 ; Mc # [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BAA ; Mc # SUNDANESE SIGN PAMAAEH
+1C24..1C2B ; Mc # [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C34..1C35 ; Mc # [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+A823..A824 ; Mc # [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A827 ; Mc # SYLOTI NAGRI VOWEL SIGN OO
+A880..A881 ; Mc # [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A8B4..A8C3 ; Mc # [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A952..A953 ; Mc # [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+AA2F..AA30 ; Mc # [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA33..AA34 ; Mc # [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA4D ; Mc # CHAM CONSONANT SIGN FINAL H
+1D165..1D166 ; Mc # [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D16D..1D172 ; Mc # [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+
+# Total code points: 236
+
+# ================================================
+
+# General_Category=Decimal_Number
+
+0030..0039 ; Nd # [10] DIGIT ZERO..DIGIT NINE
+0660..0669 ; Nd # [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+06F0..06F9 ; Nd # [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+07C0..07C9 ; Nd # [10] NKO DIGIT ZERO..NKO DIGIT NINE
+0966..096F ; Nd # [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+09E6..09EF ; Nd # [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+0A66..0A6F ; Nd # [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0AE6..0AEF ; Nd # [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0B66..0B6F ; Nd # [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0BE6..0BEF ; Nd # [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0C66..0C6F ; Nd # [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0CE6..0CEF ; Nd # [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+0D66..0D6F ; Nd # [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0E50..0E59 ; Nd # [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0ED0..0ED9 ; Nd # [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0F20..0F29 ; Nd # [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+1040..1049 ; Nd # [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+1090..1099 ; Nd # [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+17E0..17E9 ; Nd # [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+1810..1819 ; Nd # [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1946..194F ; Nd # [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+19D0..19D9 ; Nd # [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+1B50..1B59 ; Nd # [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1BB0..1BB9 ; Nd # [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+1C40..1C49 ; Nd # [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C50..1C59 ; Nd # [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+A620..A629 ; Nd # [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A8D0..A8D9 ; Nd # [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+A900..A909 ; Nd # [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+AA50..AA59 ; Nd # [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+FF10..FF19 ; Nd # [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+104A0..104A9 ; Nd # [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+1D7CE..1D7FF ; Nd # [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+
+# Total code points: 370
+
+# ================================================
+
+# General_Category=Letter_Number
+
+16EE..16F0 ; Nl # [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+2160..2182 ; Nl # [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2185..2188 ; Nl # [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+3007 ; Nl # IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; Nl # [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3038..303A ; Nl # [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+10140..10174 ; Nl # [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10341 ; Nl # GOTHIC LETTER NINETY
+1034A ; Nl # GOTHIC LETTER NINE HUNDRED
+103D1..103D5 ; Nl # [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+12400..12462 ; Nl # [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER
+
+# Total code points: 214
+
+# ================================================
+
+# General_Category=Other_Number
+
+00B2..00B3 ; No # [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+00B9 ; No # SUPERSCRIPT ONE
+00BC..00BE ; No # [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+09F4..09F9 ; No # [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+0BF0..0BF2 ; No # [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+0C78..0C7E ; No # [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+0D70..0D75 ; No # [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS
+0F2A..0F33 ; No # [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+1369..137C ; No # [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+17F0..17F9 ; No # [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+2070 ; No # SUPERSCRIPT ZERO
+2074..2079 ; No # [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE
+2080..2089 ; No # [10] SUBSCRIPT ZERO..SUBSCRIPT NINE
+2153..215F ; No # [13] VULGAR FRACTION ONE THIRD..FRACTION NUMERATOR ONE
+2460..249B ; No # [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+24EA..24FF ; No # [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO
+2776..2793 ; No # [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+2CFD ; No # COPTIC FRACTION ONE HALF
+3192..3195 ; No # [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+3220..3229 ; No # [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+3251..325F ; No # [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+3280..3289 ; No # [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+32B1..32BF ; No # [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+10107..10133 ; No # [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+10175..10178 ; No # [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+1018A ; No # GREEK ZERO SIGN
+10320..10323 ; No # [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+10916..10919 ; No # [4] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER ONE HUNDRED
+10A40..10A47 ; No # [8] KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND
+1D360..1D371 ; No # [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE
+
+# Total code points: 349
+
+# ================================================
+
+# General_Category=Space_Separator
+
+0020 ; Zs # SPACE
+00A0 ; Zs # NO-BREAK SPACE
+1680 ; Zs # OGHAM SPACE MARK
+180E ; Zs # MONGOLIAN VOWEL SEPARATOR
+2000..200A ; Zs # [11] EN QUAD..HAIR SPACE
+202F ; Zs # NARROW NO-BREAK SPACE
+205F ; Zs # MEDIUM MATHEMATICAL SPACE
+3000 ; Zs # IDEOGRAPHIC SPACE
+
+# Total code points: 18
+
+# ================================================
+
+# General_Category=Line_Separator
+
+2028 ; Zl # LINE SEPARATOR
+
+# Total code points: 1
+
+# ================================================
+
+# General_Category=Paragraph_Separator
+
+2029 ; Zp # PARAGRAPH SEPARATOR
+
+# Total code points: 1
+
+# ================================================
+
+# General_Category=Control
+
+0000..001F ; Cc # [32] <control-0000>..<control-001F>
+007F..009F ; Cc # [33] <control-007F>..<control-009F>
+
+# Total code points: 65
+
+# ================================================
+
+# General_Category=Format
+
+00AD ; Cf # SOFT HYPHEN
+0600..0603 ; Cf # [4] ARABIC NUMBER SIGN..ARABIC SIGN SAFHA
+06DD ; Cf # ARABIC END OF AYAH
+070F ; Cf # SYRIAC ABBREVIATION MARK
+17B4..17B5 ; Cf # [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+200B..200F ; Cf # [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+202A..202E ; Cf # [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+2060..2064 ; Cf # [5] WORD JOINER..INVISIBLE PLUS
+206A..206F ; Cf # [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES
+FEFF ; Cf # ZERO WIDTH NO-BREAK SPACE
+FFF9..FFFB ; Cf # [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+1D173..1D17A ; Cf # [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+E0001 ; Cf # LANGUAGE TAG
+E0020..E007F ; Cf # [96] TAG SPACE..CANCEL TAG
+
+# Total code points: 139
+
+# ================================================
+
+# General_Category=Private_Use
+
+E000..F8FF ; Co # [6400] <private-use-E000>..<private-use-F8FF>
+F0000..FFFFD ; Co # [65534] <private-use-F0000>..<private-use-FFFFD>
+100000..10FFFD; Co # [65534] <private-use-100000>..<private-use-10FFFD>
+
+# Total code points: 137468
+
+# ================================================
+
+# General_Category=Surrogate
+
+D800..DFFF ; Cs # [2048] <surrogate-D800>..<surrogate-DFFF>
+
+# Total code points: 2048
+
+# ================================================
+
+# General_Category=Dash_Punctuation
+
+002D ; Pd # HYPHEN-MINUS
+058A ; Pd # ARMENIAN HYPHEN
+05BE ; Pd # HEBREW PUNCTUATION MAQAF
+1806 ; Pd # MONGOLIAN TODO SOFT HYPHEN
+2010..2015 ; Pd # [6] HYPHEN..HORIZONTAL BAR
+2E17 ; Pd # DOUBLE OBLIQUE HYPHEN
+2E1A ; Pd # HYPHEN WITH DIAERESIS
+301C ; Pd # WAVE DASH
+3030 ; Pd # WAVY DASH
+30A0 ; Pd # KATAKANA-HIRAGANA DOUBLE HYPHEN
+FE31..FE32 ; Pd # [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+FE58 ; Pd # SMALL EM DASH
+FE63 ; Pd # SMALL HYPHEN-MINUS
+FF0D ; Pd # FULLWIDTH HYPHEN-MINUS
+
+# Total code points: 20
+
+# ================================================
+
+# General_Category=Open_Punctuation
+
+0028 ; Ps # LEFT PARENTHESIS
+005B ; Ps # LEFT SQUARE BRACKET
+007B ; Ps # LEFT CURLY BRACKET
+0F3A ; Ps # TIBETAN MARK GUG RTAGS GYON
+0F3C ; Ps # TIBETAN MARK ANG KHANG GYON
+169B ; Ps # OGHAM FEATHER MARK
+201A ; Ps # SINGLE LOW-9 QUOTATION MARK
+201E ; Ps # DOUBLE LOW-9 QUOTATION MARK
+2045 ; Ps # LEFT SQUARE BRACKET WITH QUILL
+207D ; Ps # SUPERSCRIPT LEFT PARENTHESIS
+208D ; Ps # SUBSCRIPT LEFT PARENTHESIS
+2329 ; Ps # LEFT-POINTING ANGLE BRACKET
+2768 ; Ps # MEDIUM LEFT PARENTHESIS ORNAMENT
+276A ; Ps # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+276C ; Ps # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+276E ; Ps # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+2770 ; Ps # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+2772 ; Ps # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+2774 ; Ps # MEDIUM LEFT CURLY BRACKET ORNAMENT
+27C5 ; Ps # LEFT S-SHAPED BAG DELIMITER
+27E6 ; Ps # MATHEMATICAL LEFT WHITE SQUARE BRACKET
+27E8 ; Ps # MATHEMATICAL LEFT ANGLE BRACKET
+27EA ; Ps # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+27EC ; Ps # MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+27EE ; Ps # MATHEMATICAL LEFT FLATTENED PARENTHESIS
+2983 ; Ps # LEFT WHITE CURLY BRACKET
+2985 ; Ps # LEFT WHITE PARENTHESIS
+2987 ; Ps # Z NOTATION LEFT IMAGE BRACKET
+2989 ; Ps # Z NOTATION LEFT BINDING BRACKET
+298B ; Ps # LEFT SQUARE BRACKET WITH UNDERBAR
+298D ; Ps # LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+298F ; Ps # LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2991 ; Ps # LEFT ANGLE BRACKET WITH DOT
+2993 ; Ps # LEFT ARC LESS-THAN BRACKET
+2995 ; Ps # DOUBLE LEFT ARC GREATER-THAN BRACKET
+2997 ; Ps # LEFT BLACK TORTOISE SHELL BRACKET
+29D8 ; Ps # LEFT WIGGLY FENCE
+29DA ; Ps # LEFT DOUBLE WIGGLY FENCE
+29FC ; Ps # LEFT-POINTING CURVED ANGLE BRACKET
+2E22 ; Ps # TOP LEFT HALF BRACKET
+2E24 ; Ps # BOTTOM LEFT HALF BRACKET
+2E26 ; Ps # LEFT SIDEWAYS U BRACKET
+2E28 ; Ps # LEFT DOUBLE PARENTHESIS
+3008 ; Ps # LEFT ANGLE BRACKET
+300A ; Ps # LEFT DOUBLE ANGLE BRACKET
+300C ; Ps # LEFT CORNER BRACKET
+300E ; Ps # LEFT WHITE CORNER BRACKET
+3010 ; Ps # LEFT BLACK LENTICULAR BRACKET
+3014 ; Ps # LEFT TORTOISE SHELL BRACKET
+3016 ; Ps # LEFT WHITE LENTICULAR BRACKET
+3018 ; Ps # LEFT WHITE TORTOISE SHELL BRACKET
+301A ; Ps # LEFT WHITE SQUARE BRACKET
+301D ; Ps # REVERSED DOUBLE PRIME QUOTATION MARK
+FD3E ; Ps # ORNATE LEFT PARENTHESIS
+FE17 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+FE35 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+FE37 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+FE39 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+FE3B ; Ps # PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+FE3D ; Ps # PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+FE3F ; Ps # PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+FE41 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+FE43 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+FE47 ; Ps # PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+FE59 ; Ps # SMALL LEFT PARENTHESIS
+FE5B ; Ps # SMALL LEFT CURLY BRACKET
+FE5D ; Ps # SMALL LEFT TORTOISE SHELL BRACKET
+FF08 ; Ps # FULLWIDTH LEFT PARENTHESIS
+FF3B ; Ps # FULLWIDTH LEFT SQUARE BRACKET
+FF5B ; Ps # FULLWIDTH LEFT CURLY BRACKET
+FF5F ; Ps # FULLWIDTH LEFT WHITE PARENTHESIS
+FF62 ; Ps # HALFWIDTH LEFT CORNER BRACKET
+
+# Total code points: 72
+
+# ================================================
+
+# General_Category=Close_Punctuation
+
+0029 ; Pe # RIGHT PARENTHESIS
+005D ; Pe # RIGHT SQUARE BRACKET
+007D ; Pe # RIGHT CURLY BRACKET
+0F3B ; Pe # TIBETAN MARK GUG RTAGS GYAS
+0F3D ; Pe # TIBETAN MARK ANG KHANG GYAS
+169C ; Pe # OGHAM REVERSED FEATHER MARK
+2046 ; Pe # RIGHT SQUARE BRACKET WITH QUILL
+207E ; Pe # SUPERSCRIPT RIGHT PARENTHESIS
+208E ; Pe # SUBSCRIPT RIGHT PARENTHESIS
+232A ; Pe # RIGHT-POINTING ANGLE BRACKET
+2769 ; Pe # MEDIUM RIGHT PARENTHESIS ORNAMENT
+276B ; Pe # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+276D ; Pe # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+276F ; Pe # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+2771 ; Pe # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+2773 ; Pe # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+2775 ; Pe # MEDIUM RIGHT CURLY BRACKET ORNAMENT
+27C6 ; Pe # RIGHT S-SHAPED BAG DELIMITER
+27E7 ; Pe # MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+27E9 ; Pe # MATHEMATICAL RIGHT ANGLE BRACKET
+27EB ; Pe # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+27ED ; Pe # MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+27EF ; Pe # MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+2984 ; Pe # RIGHT WHITE CURLY BRACKET
+2986 ; Pe # RIGHT WHITE PARENTHESIS
+2988 ; Pe # Z NOTATION RIGHT IMAGE BRACKET
+298A ; Pe # Z NOTATION RIGHT BINDING BRACKET
+298C ; Pe # RIGHT SQUARE BRACKET WITH UNDERBAR
+298E ; Pe # RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2990 ; Pe # RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+2992 ; Pe # RIGHT ANGLE BRACKET WITH DOT
+2994 ; Pe # RIGHT ARC GREATER-THAN BRACKET
+2996 ; Pe # DOUBLE RIGHT ARC LESS-THAN BRACKET
+2998 ; Pe # RIGHT BLACK TORTOISE SHELL BRACKET
+29D9 ; Pe # RIGHT WIGGLY FENCE
+29DB ; Pe # RIGHT DOUBLE WIGGLY FENCE
+29FD ; Pe # RIGHT-POINTING CURVED ANGLE BRACKET
+2E23 ; Pe # TOP RIGHT HALF BRACKET
+2E25 ; Pe # BOTTOM RIGHT HALF BRACKET
+2E27 ; Pe # RIGHT SIDEWAYS U BRACKET
+2E29 ; Pe # RIGHT DOUBLE PARENTHESIS
+3009 ; Pe # RIGHT ANGLE BRACKET
+300B ; Pe # RIGHT DOUBLE ANGLE BRACKET
+300D ; Pe # RIGHT CORNER BRACKET
+300F ; Pe # RIGHT WHITE CORNER BRACKET
+3011 ; Pe # RIGHT BLACK LENTICULAR BRACKET
+3015 ; Pe # RIGHT TORTOISE SHELL BRACKET
+3017 ; Pe # RIGHT WHITE LENTICULAR BRACKET
+3019 ; Pe # RIGHT WHITE TORTOISE SHELL BRACKET
+301B ; Pe # RIGHT WHITE SQUARE BRACKET
+301E..301F ; Pe # [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+FD3F ; Pe # ORNATE RIGHT PARENTHESIS
+FE18 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+FE36 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+FE38 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+FE3A ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+FE3C ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+FE3E ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+FE40 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+FE42 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+FE44 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+FE48 ; Pe # PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+FE5A ; Pe # SMALL RIGHT PARENTHESIS
+FE5C ; Pe # SMALL RIGHT CURLY BRACKET
+FE5E ; Pe # SMALL RIGHT TORTOISE SHELL BRACKET
+FF09 ; Pe # FULLWIDTH RIGHT PARENTHESIS
+FF3D ; Pe # FULLWIDTH RIGHT SQUARE BRACKET
+FF5D ; Pe # FULLWIDTH RIGHT CURLY BRACKET
+FF60 ; Pe # FULLWIDTH RIGHT WHITE PARENTHESIS
+FF63 ; Pe # HALFWIDTH RIGHT CORNER BRACKET
+
+# Total code points: 71
+
+# ================================================
+
+# General_Category=Connector_Punctuation
+
+005F ; Pc # LOW LINE
+203F..2040 ; Pc # [2] UNDERTIE..CHARACTER TIE
+2054 ; Pc # INVERTED UNDERTIE
+FE33..FE34 ; Pc # [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE4D..FE4F ; Pc # [3] DASHED LOW LINE..WAVY LOW LINE
+FF3F ; Pc # FULLWIDTH LOW LINE
+
+# Total code points: 10
+
+# ================================================
+
+# General_Category=Other_Punctuation
+
+0021..0023 ; Po # [3] EXCLAMATION MARK..NUMBER SIGN
+0025..0027 ; Po # [3] PERCENT SIGN..APOSTROPHE
+002A ; Po # ASTERISK
+002C ; Po # COMMA
+002E..002F ; Po # [2] FULL STOP..SOLIDUS
+003A..003B ; Po # [2] COLON..SEMICOLON
+003F..0040 ; Po # [2] QUESTION MARK..COMMERCIAL AT
+005C ; Po # REVERSE SOLIDUS
+00A1 ; Po # INVERTED EXCLAMATION MARK
+00B7 ; Po # MIDDLE DOT
+00BF ; Po # INVERTED QUESTION MARK
+037E ; Po # GREEK QUESTION MARK
+0387 ; Po # GREEK ANO TELEIA
+055A..055F ; Po # [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+0589 ; Po # ARMENIAN FULL STOP
+05C0 ; Po # HEBREW PUNCTUATION PASEQ
+05C3 ; Po # HEBREW PUNCTUATION SOF PASUQ
+05C6 ; Po # HEBREW PUNCTUATION NUN HAFUKHA
+05F3..05F4 ; Po # [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+0609..060A ; Po # [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+060C..060D ; Po # [2] ARABIC COMMA..ARABIC DATE SEPARATOR
+061B ; Po # ARABIC SEMICOLON
+061E..061F ; Po # [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
+066A..066D ; Po # [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+06D4 ; Po # ARABIC FULL STOP
+0700..070D ; Po # [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+07F7..07F9 ; Po # [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+0964..0965 ; Po # [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+0970 ; Po # DEVANAGARI ABBREVIATION SIGN
+0DF4 ; Po # SINHALA PUNCTUATION KUNDDALIYA
+0E4F ; Po # THAI CHARACTER FONGMAN
+0E5A..0E5B ; Po # [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+0F04..0F12 ; Po # [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+0F85 ; Po # TIBETAN MARK PALUTA
+0FD0..0FD4 ; Po # [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+104A..104F ; Po # [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+10FB ; Po # GEORGIAN PARAGRAPH SEPARATOR
+1361..1368 ; Po # [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR
+166D..166E ; Po # [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP
+16EB..16ED ; Po # [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+1735..1736 ; Po # [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+17D4..17D6 ; Po # [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+17D8..17DA ; Po # [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+1800..1805 ; Po # [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS
+1807..180A ; Po # [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+1944..1945 ; Po # [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+19DE..19DF ; Po # [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+1A1E..1A1F ; Po # [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+1B5A..1B60 ; Po # [7] BALINESE PANTI..BALINESE PAMENENG
+1C3B..1C3F ; Po # [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+1C7E..1C7F ; Po # [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+2016..2017 ; Po # [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE
+2020..2027 ; Po # [8] DAGGER..HYPHENATION POINT
+2030..2038 ; Po # [9] PER MILLE SIGN..CARET
+203B..203E ; Po # [4] REFERENCE MARK..OVERLINE
+2041..2043 ; Po # [3] CARET INSERTION POINT..HYPHEN BULLET
+2047..2051 ; Po # [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+2053 ; Po # SWUNG DASH
+2055..205E ; Po # [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+2CF9..2CFC ; Po # [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+2CFE..2CFF ; Po # [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+2E00..2E01 ; Po # [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+2E06..2E08 ; Po # [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+2E0B ; Po # RAISED SQUARE
+2E0E..2E16 ; Po # [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+2E18..2E19 ; Po # [2] INVERTED INTERROBANG..PALM BRANCH
+2E1B ; Po # TILDE WITH RING ABOVE
+2E1E..2E1F ; Po # [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+2E2A..2E2E ; Po # [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+2E30 ; Po # RING POINT
+3001..3003 ; Po # [3] IDEOGRAPHIC COMMA..DITTO MARK
+303D ; Po # PART ALTERNATION MARK
+30FB ; Po # KATAKANA MIDDLE DOT
+A60D..A60F ; Po # [3] VAI COMMA..VAI QUESTION MARK
+A673 ; Po # SLAVONIC ASTERISK
+A67E ; Po # CYRILLIC KAVYKA
+A874..A877 ; Po # [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+A8CE..A8CF ; Po # [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+A92E..A92F ; Po # [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+A95F ; Po # REJANG SECTION MARK
+AA5C..AA5F ; Po # [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+FE10..FE16 ; Po # [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+FE19 ; Po # PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+FE30 ; Po # PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+FE45..FE46 ; Po # [2] SESAME DOT..WHITE SESAME DOT
+FE49..FE4C ; Po # [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+FE50..FE52 ; Po # [3] SMALL COMMA..SMALL FULL STOP
+FE54..FE57 ; Po # [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+FE5F..FE61 ; Po # [3] SMALL NUMBER SIGN..SMALL ASTERISK
+FE68 ; Po # SMALL REVERSE SOLIDUS
+FE6A..FE6B ; Po # [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+FF01..FF03 ; Po # [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+FF05..FF07 ; Po # [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+FF0A ; Po # FULLWIDTH ASTERISK
+FF0C ; Po # FULLWIDTH COMMA
+FF0E..FF0F ; Po # [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+FF1A..FF1B ; Po # [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+FF1F..FF20 ; Po # [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+FF3C ; Po # FULLWIDTH REVERSE SOLIDUS
+FF61 ; Po # HALFWIDTH IDEOGRAPHIC FULL STOP
+FF64..FF65 ; Po # [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+10100..10101 ; Po # [2] AEGEAN WORD SEPARATOR LINE..AEGEAN WORD SEPARATOR DOT
+1039F ; Po # UGARITIC WORD DIVIDER
+103D0 ; Po # OLD PERSIAN WORD DIVIDER
+1091F ; Po # PHOENICIAN WORD SEPARATOR
+1093F ; Po # LYDIAN TRIANGULAR MARK
+10A50..10A58 ; Po # [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+12470..12473 ; Po # [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON
+
+# Total code points: 315
+
+# ================================================
+
+# General_Category=Math_Symbol
+
+002B ; Sm # PLUS SIGN
+003C..003E ; Sm # [3] LESS-THAN SIGN..GREATER-THAN SIGN
+007C ; Sm # VERTICAL LINE
+007E ; Sm # TILDE
+00AC ; Sm # NOT SIGN
+00B1 ; Sm # PLUS-MINUS SIGN
+00D7 ; Sm # MULTIPLICATION SIGN
+00F7 ; Sm # DIVISION SIGN
+03F6 ; Sm # GREEK REVERSED LUNATE EPSILON SYMBOL
+0606..0608 ; Sm # [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+2044 ; Sm # FRACTION SLASH
+2052 ; Sm # COMMERCIAL MINUS SIGN
+207A..207C ; Sm # [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+208A..208C ; Sm # [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+2140..2144 ; Sm # [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+214B ; Sm # TURNED AMPERSAND
+2190..2194 ; Sm # [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+219A..219B ; Sm # [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+21A0 ; Sm # RIGHTWARDS TWO HEADED ARROW
+21A3 ; Sm # RIGHTWARDS ARROW WITH TAIL
+21A6 ; Sm # RIGHTWARDS ARROW FROM BAR
+21AE ; Sm # LEFT RIGHT ARROW WITH STROKE
+21CE..21CF ; Sm # [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+21D2 ; Sm # RIGHTWARDS DOUBLE ARROW
+21D4 ; Sm # LEFT RIGHT DOUBLE ARROW
+21F4..22FF ; Sm # [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
+2308..230B ; Sm # [4] LEFT CEILING..RIGHT FLOOR
+2320..2321 ; Sm # [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+237C ; Sm # RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+239B..23B3 ; Sm # [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+23DC..23E1 ; Sm # [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+25B7 ; Sm # WHITE RIGHT-POINTING TRIANGLE
+25C1 ; Sm # WHITE LEFT-POINTING TRIANGLE
+25F8..25FF ; Sm # [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+266F ; Sm # MUSIC SHARP SIGN
+27C0..27C4 ; Sm # [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+27C7..27CA ; Sm # [4] OR WITH DOT INSIDE..VERTICAL BAR WITH HORIZONTAL STROKE
+27CC ; Sm # LONG DIVISION
+27D0..27E5 ; Sm # [22] WHITE DIAMOND WITH CENTRED DOT..WHITE SQUARE WITH RIGHTWARDS TICK
+27F0..27FF ; Sm # [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+2900..2982 ; Sm # [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON
+2999..29D7 ; Sm # [63] DOTTED FENCE..BLACK HOURGLASS
+29DC..29FB ; Sm # [32] INCOMPLETE INFINITY..TRIPLE PLUS
+29FE..2AFF ; Sm # [258] TINY..N-ARY WHITE VERTICAL BAR
+2B30..2B44 ; Sm # [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+2B47..2B4C ; Sm # [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+FB29 ; Sm # HEBREW LETTER ALTERNATIVE PLUS SIGN
+FE62 ; Sm # SMALL PLUS SIGN
+FE64..FE66 ; Sm # [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+FF0B ; Sm # FULLWIDTH PLUS SIGN
+FF1C..FF1E ; Sm # [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+FF5C ; Sm # FULLWIDTH VERTICAL LINE
+FF5E ; Sm # FULLWIDTH TILDE
+FFE2 ; Sm # FULLWIDTH NOT SIGN
+FFE9..FFEC ; Sm # [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+1D6C1 ; Sm # MATHEMATICAL BOLD NABLA
+1D6DB ; Sm # MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+1D6FB ; Sm # MATHEMATICAL ITALIC NABLA
+1D715 ; Sm # MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+1D735 ; Sm # MATHEMATICAL BOLD ITALIC NABLA
+1D74F ; Sm # MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+1D76F ; Sm # MATHEMATICAL SANS-SERIF BOLD NABLA
+1D789 ; Sm # MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+1D7A9 ; Sm # MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+1D7C3 ; Sm # MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+
+# Total code points: 945
+
+# ================================================
+
+# General_Category=Currency_Symbol
+
+0024 ; Sc # DOLLAR SIGN
+00A2..00A5 ; Sc # [4] CENT SIGN..YEN SIGN
+060B ; Sc # AFGHANI SIGN
+09F2..09F3 ; Sc # [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+0AF1 ; Sc # GUJARATI RUPEE SIGN
+0BF9 ; Sc # TAMIL RUPEE SIGN
+0E3F ; Sc # THAI CURRENCY SYMBOL BAHT
+17DB ; Sc # KHMER CURRENCY SYMBOL RIEL
+20A0..20B5 ; Sc # [22] EURO-CURRENCY SIGN..CEDI SIGN
+FDFC ; Sc # RIAL SIGN
+FE69 ; Sc # SMALL DOLLAR SIGN
+FF04 ; Sc # FULLWIDTH DOLLAR SIGN
+FFE0..FFE1 ; Sc # [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+FFE5..FFE6 ; Sc # [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+
+# Total code points: 41
+
+# ================================================
+
+# General_Category=Modifier_Symbol
+
+005E ; Sk # CIRCUMFLEX ACCENT
+0060 ; Sk # GRAVE ACCENT
+00A8 ; Sk # DIAERESIS
+00AF ; Sk # MACRON
+00B4 ; Sk # ACUTE ACCENT
+00B8 ; Sk # CEDILLA
+02C2..02C5 ; Sk # [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02D2..02DF ; Sk # [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT
+02E5..02EB ; Sk # [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02ED ; Sk # MODIFIER LETTER UNASPIRATED
+02EF..02FF ; Sk # [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+0375 ; Sk # GREEK LOWER NUMERAL SIGN
+0384..0385 ; Sk # [2] GREEK TONOS..GREEK DIALYTIKA TONOS
+1FBD ; Sk # GREEK KORONIS
+1FBF..1FC1 ; Sk # [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+1FCD..1FCF ; Sk # [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+1FDD..1FDF ; Sk # [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+1FED..1FEF ; Sk # [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+1FFD..1FFE ; Sk # [2] GREEK OXIA..GREEK DASIA
+309B..309C ; Sk # [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+A700..A716 ; Sk # [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A720..A721 ; Sk # [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A789..A78A ; Sk # [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+FF3E ; Sk # FULLWIDTH CIRCUMFLEX ACCENT
+FF40 ; Sk # FULLWIDTH GRAVE ACCENT
+FFE3 ; Sk # FULLWIDTH MACRON
+
+# Total code points: 99
+
+# ================================================
+
+# General_Category=Other_Symbol
+
+00A6..00A7 ; So # [2] BROKEN BAR..SECTION SIGN
+00A9 ; So # COPYRIGHT SIGN
+00AE ; So # REGISTERED SIGN
+00B0 ; So # DEGREE SIGN
+00B6 ; So # PILCROW SIGN
+0482 ; So # CYRILLIC THOUSANDS SIGN
+060E..060F ; So # [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+06E9 ; So # ARABIC PLACE OF SAJDAH
+06FD..06FE ; So # [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+07F6 ; So # NKO SYMBOL OO DENNEN
+09FA ; So # BENGALI ISSHAR
+0B70 ; So # ORIYA ISSHAR
+0BF3..0BF8 ; So # [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+0BFA ; So # TAMIL NUMBER SIGN
+0C7F ; So # TELUGU SIGN TUUMU
+0CF1..0CF2 ; So # [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0D79 ; So # MALAYALAM DATE MARK
+0F01..0F03 ; So # [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+0F13..0F17 ; So # [5] TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+0F1A..0F1F ; So # [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+0F34 ; So # TIBETAN MARK BSDUS RTAGS
+0F36 ; So # TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+0F38 ; So # TIBETAN MARK CHE MGO
+0FBE..0FC5 ; So # [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+0FC7..0FCC ; So # [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+0FCE..0FCF ; So # [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+109E..109F ; So # [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+1360 ; So # ETHIOPIC SECTION MARK
+1390..1399 ; So # [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+1940 ; So # LIMBU SIGN LOO
+19E0..19FF ; So # [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+1B61..1B6A ; So # [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+1B74..1B7C ; So # [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+2100..2101 ; So # [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+2103..2106 ; So # [4] DEGREE CELSIUS..CADA UNA
+2108..2109 ; So # [2] SCRUPLE..DEGREE FAHRENHEIT
+2114 ; So # L B BAR SYMBOL
+2116..2118 ; So # [3] NUMERO SIGN..SCRIPT CAPITAL P
+211E..2123 ; So # [6] PRESCRIPTION TAKE..VERSICLE
+2125 ; So # OUNCE SIGN
+2127 ; So # INVERTED OHM SIGN
+2129 ; So # TURNED GREEK SMALL LETTER IOTA
+212E ; So # ESTIMATED SYMBOL
+213A..213B ; So # [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+214A ; So # PROPERTY LINE
+214C..214D ; So # [2] PER SIGN..AKTIESELSKAB
+214F ; So # SYMBOL FOR SAMARITAN SOURCE
+2195..2199 ; So # [5] UP DOWN ARROW..SOUTH WEST ARROW
+219C..219F ; So # [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+21A1..21A2 ; So # [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+21A4..21A5 ; So # [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+21A7..21AD ; So # [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+21AF..21CD ; So # [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+21D0..21D1 ; So # [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+21D3 ; So # DOWNWARDS DOUBLE ARROW
+21D5..21F3 ; So # [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
+2300..2307 ; So # [8] DIAMETER SIGN..WAVY LINE
+230C..231F ; So # [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
+2322..2328 ; So # [7] FROWN..KEYBOARD
+232B..237B ; So # [81] ERASE TO THE LEFT..NOT CHECK MARK
+237D..239A ; So # [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+23B4..23DB ; So # [40] TOP SQUARE BRACKET..FUSE
+23E2..23E7 ; So # [6] WHITE TRAPEZIUM..ELECTRICAL INTERSECTION
+2400..2426 ; So # [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+2440..244A ; So # [11] OCR HOOK..OCR DOUBLE BACKSLASH
+249C..24E9 ; So # [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+2500..25B6 ; So # [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE
+25B8..25C0 ; So # [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE
+25C2..25F7 ; So # [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+2600..266E ; So # [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
+2670..269D ; So # [46] WEST SYRIAC CROSS..OUTLINED WHITE STAR
+26A0..26BC ; So # [29] WARNING SIGN..SESQUIQUADRATE
+26C0..26C3 ; So # [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+2701..2704 ; So # [4] UPPER BLADE SCISSORS..WHITE SCISSORS
+2706..2709 ; So # [4] TELEPHONE LOCATION SIGN..ENVELOPE
+270C..2727 ; So # [28] VICTORY HAND..WHITE FOUR POINTED STAR
+2729..274B ; So # [35] STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+274D ; So # SHADOWED WHITE CIRCLE
+274F..2752 ; So # [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE
+2756 ; So # BLACK DIAMOND MINUS WHITE X
+2758..275E ; So # [7] LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
+2761..2767 ; So # [7] CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET
+2794 ; So # HEAVY WIDE-HEADED RIGHTWARDS ARROW
+2798..27AF ; So # [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+27B1..27BE ; So # [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW
+2800..28FF ; So # [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+2B00..2B2F ; So # [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE
+2B45..2B46 ; So # [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+2B50..2B54 ; So # [5] WHITE MEDIUM STAR..WHITE RIGHT-POINTING PENTAGON
+2CE5..2CEA ; So # [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+2E80..2E99 ; So # [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+2E9B..2EF3 ; So # [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+2F00..2FD5 ; So # [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+2FF0..2FFB ; So # [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+3004 ; So # JAPANESE INDUSTRIAL STANDARD SYMBOL
+3012..3013 ; So # [2] POSTAL MARK..GETA MARK
+3020 ; So # POSTAL MARK FACE
+3036..3037 ; So # [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+303E..303F ; So # [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
+3190..3191 ; So # [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+3196..319F ; So # [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+31C0..31E3 ; So # [36] CJK STROKE T..CJK STROKE Q
+3200..321E ; So # [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+322A..3243 ; So # [26] PARENTHESIZED IDEOGRAPH MOON..PARENTHESIZED IDEOGRAPH REACH
+3250 ; So # PARTNERSHIP SIGN
+3260..327F ; So # [32] CIRCLED HANGUL KIYEOK..KOREAN STANDARD SYMBOL
+328A..32B0 ; So # [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+32C0..32FE ; So # [63] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..CIRCLED KATAKANA WO
+3300..33FF ; So # [256] SQUARE APAATO..SQUARE GAL
+4DC0..4DFF ; So # [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+A490..A4C6 ; So # [55] YI RADICAL QOT..YI RADICAL KE
+A828..A82B ; So # [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+FDFD ; So # ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
+FFE4 ; So # FULLWIDTH BROKEN BAR
+FFE8 ; So # HALFWIDTH FORMS LIGHT VERTICAL
+FFED..FFEE ; So # [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+FFFC..FFFD ; So # [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER
+10102 ; So # AEGEAN CHECK MARK
+10137..1013F ; So # [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+10179..10189 ; So # [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+10190..1019B ; So # [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
+101D0..101FC ; So # [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+1D000..1D0F5 ; So # [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+1D100..1D126 ; So # [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+1D129..1D164 ; So # [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+1D16A..1D16C ; So # [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+1D183..1D184 ; So # [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+1D18C..1D1A9 ; So # [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+1D1AE..1D1DD ; So # [48] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL PES SUBPUNCTIS
+1D200..1D241 ; So # [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+1D245 ; So # GREEK MUSICAL LEIMMA
+1D300..1D356 ; So # [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+1F000..1F02B ; So # [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F030..1F093 ; So # [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+
+# Total code points: 3225
+
+# ================================================
+
+# General_Category=Initial_Punctuation
+
+00AB ; Pi # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+2018 ; Pi # LEFT SINGLE QUOTATION MARK
+201B..201C ; Pi # [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK
+201F ; Pi # DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+2039 ; Pi # SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+2E02 ; Pi # LEFT SUBSTITUTION BRACKET
+2E04 ; Pi # LEFT DOTTED SUBSTITUTION BRACKET
+2E09 ; Pi # LEFT TRANSPOSITION BRACKET
+2E0C ; Pi # LEFT RAISED OMISSION BRACKET
+2E1C ; Pi # LEFT LOW PARAPHRASE BRACKET
+2E20 ; Pi # LEFT VERTICAL BAR WITH QUILL
+
+# Total code points: 12
+
+# ================================================
+
+# General_Category=Final_Punctuation
+
+00BB ; Pf # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+2019 ; Pf # RIGHT SINGLE QUOTATION MARK
+201D ; Pf # RIGHT DOUBLE QUOTATION MARK
+203A ; Pf # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+2E03 ; Pf # RIGHT SUBSTITUTION BRACKET
+2E05 ; Pf # RIGHT DOTTED SUBSTITUTION BRACKET
+2E0A ; Pf # RIGHT TRANSPOSITION BRACKET
+2E0D ; Pf # RIGHT RAISED OMISSION BRACKET
+2E1D ; Pf # RIGHT LOW PARAPHRASE BRACKET
+2E21 ; Pf # RIGHT VERTICAL BAR WITH QUILL
+
+# Total code points: 10
+
+# EOF
diff --git a/third_party/harfbuzz/contrib/tables/GraphemeBreakProperty.txt b/third_party/harfbuzz/contrib/tables/GraphemeBreakProperty.txt
new file mode 100644
index 0000000..50477a1
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/GraphemeBreakProperty.txt
@@ -0,0 +1,1166 @@
+# GraphemeBreakProperty-5.1.0.txt
+# Date: 2008-03-03, 21:57:47 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2008 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+
+# ================================================
+
+# Property: Grapheme_Cluster_Break
+
+# All code points not explicitly listed for Grapheme_Cluster_Break
+# have the value Other (XX).
+
+# @missing: 0000..10FFFF; Other
+
+# ================================================
+
+000D ; CR # Cc <control-000D>
+
+# Total code points: 1
+
+# ================================================
+
+000A ; LF # Cc <control-000A>
+
+# Total code points: 1
+
+# ================================================
+
+0000..0009 ; Control # Cc [10] <control-0000>..<control-0009>
+000B..000C ; Control # Cc [2] <control-000B>..<control-000C>
+000E..001F ; Control # Cc [18] <control-000E>..<control-001F>
+007F..009F ; Control # Cc [33] <control-007F>..<control-009F>
+00AD ; Control # Cf SOFT HYPHEN
+0600..0603 ; Control # Cf [4] ARABIC NUMBER SIGN..ARABIC SIGN SAFHA
+06DD ; Control # Cf ARABIC END OF AYAH
+070F ; Control # Cf SYRIAC ABBREVIATION MARK
+17B4..17B5 ; Control # Cf [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+200B ; Control # Cf ZERO WIDTH SPACE
+200E..200F ; Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+2028 ; Control # Zl LINE SEPARATOR
+2029 ; Control # Zp PARAGRAPH SEPARATOR
+202A..202E ; Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+2060..2064 ; Control # Cf [5] WORD JOINER..INVISIBLE PLUS
+206A..206F ; Control # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES
+FEFF ; Control # Cf ZERO WIDTH NO-BREAK SPACE
+FFF9..FFFB ; Control # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+1D173..1D17A ; Control # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+E0001 ; Control # Cf LANGUAGE TAG
+E0020..E007F ; Control # Cf [96] TAG SPACE..CANCEL TAG
+
+# Total code points: 202
+
+# ================================================
+
+0300..036F ; Extend # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+0483..0487 ; Extend # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0488..0489 ; Extend # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+0591..05BD ; Extend # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BF ; Extend # Mn HEBREW POINT RAFE
+05C1..05C2 ; Extend # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C4..05C5 ; Extend # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C7 ; Extend # Mn HEBREW POINT QAMATS QATAN
+0610..061A ; Extend # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+064B..065E ; Extend # Mn [20] ARABIC FATHATAN..ARABIC FATHA WITH TWO DOTS
+0670 ; Extend # Mn ARABIC LETTER SUPERSCRIPT ALEF
+06D6..06DC ; Extend # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DE ; Extend # Me ARABIC START OF RUB EL HIZB
+06DF..06E4 ; Extend # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E7..06E8 ; Extend # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06EA..06ED ; Extend # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+0711 ; Extend # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+0901..0902 ; Extend # Mn [2] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+093C ; Extend # Mn DEVANAGARI SIGN NUKTA
+0941..0948 ; Extend # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+094D ; Extend # Mn DEVANAGARI SIGN VIRAMA
+0951..0954 ; Extend # Mn [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT
+0962..0963 ; Extend # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0981 ; Extend # Mn BENGALI SIGN CANDRABINDU
+09BC ; Extend # Mn BENGALI SIGN NUKTA
+09BE ; Extend # Mc BENGALI VOWEL SIGN AA
+09C1..09C4 ; Extend # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09CD ; Extend # Mn BENGALI SIGN VIRAMA
+09D7 ; Extend # Mc BENGALI AU LENGTH MARK
+09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A3C ; Extend # Mn GURMUKHI SIGN NUKTA
+0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Extend # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Extend # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Extend # Mn GURMUKHI SIGN UDAAT
+0A70..0A71 ; Extend # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A75 ; Extend # Mn GURMUKHI SIGN YAKASH
+0A81..0A82 ; Extend # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0ABC ; Extend # Mn GUJARATI SIGN NUKTA
+0AC1..0AC5 ; Extend # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Extend # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0ACD ; Extend # Mn GUJARATI SIGN VIRAMA
+0AE2..0AE3 ; Extend # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0B01 ; Extend # Mn ORIYA SIGN CANDRABINDU
+0B3C ; Extend # Mn ORIYA SIGN NUKTA
+0B3E ; Extend # Mc ORIYA VOWEL SIGN AA
+0B3F ; Extend # Mn ORIYA VOWEL SIGN I
+0B41..0B44 ; Extend # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B4D ; Extend # Mn ORIYA SIGN VIRAMA
+0B56 ; Extend # Mn ORIYA AI LENGTH MARK
+0B57 ; Extend # Mc ORIYA AU LENGTH MARK
+0B62..0B63 ; Extend # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B82 ; Extend # Mn TAMIL SIGN ANUSVARA
+0BBE ; Extend # Mc TAMIL VOWEL SIGN AA
+0BC0 ; Extend # Mn TAMIL VOWEL SIGN II
+0BCD ; Extend # Mn TAMIL SIGN VIRAMA
+0BD7 ; Extend # Mc TAMIL AU LENGTH MARK
+0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Extend # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C62..0C63 ; Extend # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0CBC ; Extend # Mn KANNADA SIGN NUKTA
+0CBF ; Extend # Mn KANNADA VOWEL SIGN I
+0CC2 ; Extend # Mc KANNADA VOWEL SIGN UU
+0CC6 ; Extend # Mn KANNADA VOWEL SIGN E
+0CCC..0CCD ; Extend # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; Extend # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CE2..0CE3 ; Extend # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0D3E ; Extend # Mc MALAYALAM VOWEL SIGN AA
+0D41..0D44 ; Extend # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D4D ; Extend # Mn MALAYALAM SIGN VIRAMA
+0D57 ; Extend # Mc MALAYALAM AU LENGTH MARK
+0D62..0D63 ; Extend # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0DCA ; Extend # Mn SINHALA SIGN AL-LAKUNA
+0DCF ; Extend # Mc SINHALA VOWEL SIGN AELA-PILLA
+0DD2..0DD4 ; Extend # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Extend # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DDF ; Extend # Mc SINHALA VOWEL SIGN GAYANUKITTA
+0E30 ; Extend # Lo THAI CHARACTER SARA A
+0E31 ; Extend # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; Extend # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E3A ; Extend # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E45 ; Extend # Lo THAI CHARACTER LAKKHANGYAO
+0E47..0E4E ; Extend # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0EB0 ; Extend # Lo LAO VOWEL SIGN A
+0EB1 ; Extend # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; Extend # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB9 ; Extend # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Extend # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EC8..0ECD ; Extend # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0F18..0F19 ; Extend # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F35 ; Extend # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F37 ; Extend # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F39 ; Extend # Mn TIBETAN MARK TSA -PHRU
+0F71..0F7E ; Extend # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F80..0F84 ; Extend # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F86..0F87 ; Extend # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F90..0F97 ; Extend # Mn [8] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Extend # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FC6 ; Extend # Mn TIBETAN SYMBOL PADMA GDAN
+102D..1030 ; Extend # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1032..1037 ; Extend # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1039..103A ; Extend # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103D..103E ; Extend # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+1058..1059 ; Extend # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105E..1060 ; Extend # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1071..1074 ; Extend # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1082 ; Extend # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1085..1086 ; Extend # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+108D ; Extend # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+135F ; Extend # Mn ETHIOPIC COMBINING GEMINATION MARK
+1712..1714 ; Extend # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+1732..1734 ; Extend # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+1752..1753 ; Extend # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+1772..1773 ; Extend # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+17B7..17BD ; Extend # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17C6 ; Extend # Mn KHMER SIGN NIKAHIT
+17C9..17D3 ; Extend # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17DD ; Extend # Mn KHMER SIGN ATTHACAN
+180B..180D ; Extend # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+18A9 ; Extend # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+1920..1922 ; Extend # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1927..1928 ; Extend # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1932 ; Extend # Mn LIMBU SMALL LETTER ANUSVARA
+1939..193B ; Extend # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1A17..1A18 ; Extend # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B34 ; Extend # Mn BALINESE SIGN REREKAN
+1B36..1B3A ; Extend # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3C ; Extend # Mn BALINESE VOWEL SIGN LA LENGA
+1B42 ; Extend # Mn BALINESE VOWEL SIGN PEPET
+1B6B..1B73 ; Extend # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B80..1B81 ; Extend # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1BA2..1BA5 ; Extend # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA8..1BA9 ; Extend # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1C2C..1C33 ; Extend # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C36..1C37 ; Extend # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1DC0..1DE6 ; Extend # Mn [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z
+1DFE..1DFF ; Extend # Mn [2] COMBINING LEFT ARROWHEAD ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+200C..200D ; Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER
+20D0..20DC ; Extend # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20DD..20E0 ; Extend # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E1 ; Extend # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E2..20E4 ; Extend # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+20E5..20F0 ; Extend # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+2DE0..2DFF ; Extend # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+302A..302F ; Extend # Mn [6] IDEOGRAPHIC LEVEL TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3099..309A ; Extend # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+A66F ; Extend # Mn COMBINING CYRILLIC VZMET
+A670..A672 ; Extend # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A67C..A67D ; Extend # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
+A802 ; Extend # Mn SYLOTI NAGRI SIGN DVISVARA
+A806 ; Extend # Mn SYLOTI NAGRI SIGN HASANTA
+A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA
+A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A8C4 ; Extend # Mn SAURASHTRA SIGN VIRAMA
+A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+AA29..AA2E ; Extend # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA31..AA32 ; Extend # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA35..AA36 ; Extend # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA43 ; Extend # Mn CHAM CONSONANT SIGN FINAL NG
+AA4C ; Extend # Mn CHAM CONSONANT SIGN FINAL M
+FB1E ; Extend # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FE00..FE0F ; Extend # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE26 ; Extend # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
+FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+101FD ; Extend # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+10A01..10A03 ; Extend # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Extend # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Extend # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Extend # Mn KHAROSHTHI VIRAMA
+1D165 ; Extend # Mc MUSICAL SYMBOL COMBINING STEM
+1D167..1D169 ; Extend # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D16E..1D172 ; Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
+1D17B..1D182 ; Extend # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Extend # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Extend # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+1D242..1D244 ; Extend # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 1075
+
+# ================================================
+
+0E40..0E44 ; Prepend # Lo [5] THAI CHARACTER SARA E..THAI CHARACTER SARA AI MAIMALAI
+0EC0..0EC4 ; Prepend # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+
+# Total code points: 10
+
+# ================================================
+
+0903 ; SpacingMark # Mc DEVANAGARI SIGN VISARGA
+093E..0940 ; SpacingMark # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0949..094C ; SpacingMark # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+0982..0983 ; SpacingMark # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+09BF..09C0 ; SpacingMark # Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II
+09C7..09C8 ; SpacingMark # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; SpacingMark # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+0A03 ; SpacingMark # Mc GURMUKHI SIGN VISARGA
+0A3E..0A40 ; SpacingMark # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A83 ; SpacingMark # Mc GUJARATI SIGN VISARGA
+0ABE..0AC0 ; SpacingMark # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC9 ; SpacingMark # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; SpacingMark # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0B02..0B03 ; SpacingMark # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B40 ; SpacingMark # Mc ORIYA VOWEL SIGN II
+0B47..0B48 ; SpacingMark # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; SpacingMark # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0BBF ; SpacingMark # Mc TAMIL VOWEL SIGN I
+0BC1..0BC2 ; SpacingMark # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; SpacingMark # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; SpacingMark # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0C01..0C03 ; SpacingMark # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C41..0C44 ; SpacingMark # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C82..0C83 ; SpacingMark # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0CBE ; SpacingMark # Mc KANNADA VOWEL SIGN AA
+0CC0..0CC1 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U
+0CC3..0CC4 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR
+0CC7..0CC8 ; SpacingMark # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; SpacingMark # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0D02..0D03 ; SpacingMark # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D3F..0D40 ; SpacingMark # Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II
+0D46..0D48 ; SpacingMark # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; SpacingMark # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D82..0D83 ; SpacingMark # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0DD0..0DD1 ; SpacingMark # Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD8..0DDE ; SpacingMark # Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA
+0DF2..0DF3 ; SpacingMark # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0F3E..0F3F ; SpacingMark # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F7F ; SpacingMark # Mc TIBETAN SIGN RNAM BCAD
+102B..102C ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+1031 ; SpacingMark # Mc MYANMAR VOWEL SIGN E
+1038 ; SpacingMark # Mc MYANMAR SIGN VISARGA
+103B..103C ; SpacingMark # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+1056..1057 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1062..1064 ; SpacingMark # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1067..106D ; SpacingMark # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+1083..1084 ; SpacingMark # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1087..108C ; SpacingMark # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108F ; SpacingMark # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+17B6 ; SpacingMark # Mc KHMER VOWEL SIGN AA
+17BE..17C5 ; SpacingMark # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C7..17C8 ; SpacingMark # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+1923..1926 ; SpacingMark # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1929..192B ; SpacingMark # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; SpacingMark # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1933..1938 ; SpacingMark # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+19B0..19C0 ; SpacingMark # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY
+19C8..19C9 ; SpacingMark # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2
+1A19..1A1B ; SpacingMark # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
+1B04 ; SpacingMark # Mc BALINESE SIGN BISAH
+1B35 ; SpacingMark # Mc BALINESE VOWEL SIGN TEDUNG
+1B3B ; SpacingMark # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3D..1B41 ; SpacingMark # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B43..1B44 ; SpacingMark # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B82 ; SpacingMark # Mc SUNDANESE SIGN PANGWISAD
+1BA1 ; SpacingMark # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA6..1BA7 ; SpacingMark # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BAA ; SpacingMark # Mc SUNDANESE SIGN PAMAAEH
+1C24..1C2B ; SpacingMark # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C34..1C35 ; SpacingMark # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+A823..A824 ; SpacingMark # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A827 ; SpacingMark # Mc SYLOTI NAGRI VOWEL SIGN OO
+A880..A881 ; SpacingMark # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A8B4..A8C3 ; SpacingMark # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A952..A953 ; SpacingMark # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+AA2F..AA30 ; SpacingMark # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA33..AA34 ; SpacingMark # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA4D ; SpacingMark # Mc CHAM CONSONANT SIGN FINAL H
+1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
+
+# Total code points: 217
+
+# ================================================
+
+1100..1159 ; L # Lo [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH
+115F ; L # Lo HANGUL CHOSEONG FILLER
+
+# Total code points: 91
+
+# ================================================
+
+1160..11A2 ; V # Lo [67] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG SSANGARAEA
+
+# Total code points: 67
+
+# ================================================
+
+11A8..11F9 ; T # Lo [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH
+
+# Total code points: 82
+
+# ================================================
+
+AC00 ; LV # Lo HANGUL SYLLABLE GA
+AC1C ; LV # Lo HANGUL SYLLABLE GAE
+AC38 ; LV # Lo HANGUL SYLLABLE GYA
+AC54 ; LV # Lo HANGUL SYLLABLE GYAE
+AC70 ; LV # Lo HANGUL SYLLABLE GEO
+AC8C ; LV # Lo HANGUL SYLLABLE GE
+ACA8 ; LV # Lo HANGUL SYLLABLE GYEO
+ACC4 ; LV # Lo HANGUL SYLLABLE GYE
+ACE0 ; LV # Lo HANGUL SYLLABLE GO
+ACFC ; LV # Lo HANGUL SYLLABLE GWA
+AD18 ; LV # Lo HANGUL SYLLABLE GWAE
+AD34 ; LV # Lo HANGUL SYLLABLE GOE
+AD50 ; LV # Lo HANGUL SYLLABLE GYO
+AD6C ; LV # Lo HANGUL SYLLABLE GU
+AD88 ; LV # Lo HANGUL SYLLABLE GWEO
+ADA4 ; LV # Lo HANGUL SYLLABLE GWE
+ADC0 ; LV # Lo HANGUL SYLLABLE GWI
+ADDC ; LV # Lo HANGUL SYLLABLE GYU
+ADF8 ; LV # Lo HANGUL SYLLABLE GEU
+AE14 ; LV # Lo HANGUL SYLLABLE GYI
+AE30 ; LV # Lo HANGUL SYLLABLE GI
+AE4C ; LV # Lo HANGUL SYLLABLE GGA
+AE68 ; LV # Lo HANGUL SYLLABLE GGAE
+AE84 ; LV # Lo HANGUL SYLLABLE GGYA
+AEA0 ; LV # Lo HANGUL SYLLABLE GGYAE
+AEBC ; LV # Lo HANGUL SYLLABLE GGEO
+AED8 ; LV # Lo HANGUL SYLLABLE GGE
+AEF4 ; LV # Lo HANGUL SYLLABLE GGYEO
+AF10 ; LV # Lo HANGUL SYLLABLE GGYE
+AF2C ; LV # Lo HANGUL SYLLABLE GGO
+AF48 ; LV # Lo HANGUL SYLLABLE GGWA
+AF64 ; LV # Lo HANGUL SYLLABLE GGWAE
+AF80 ; LV # Lo HANGUL SYLLABLE GGOE
+AF9C ; LV # Lo HANGUL SYLLABLE GGYO
+AFB8 ; LV # Lo HANGUL SYLLABLE GGU
+AFD4 ; LV # Lo HANGUL SYLLABLE GGWEO
+AFF0 ; LV # Lo HANGUL SYLLABLE GGWE
+B00C ; LV # Lo HANGUL SYLLABLE GGWI
+B028 ; LV # Lo HANGUL SYLLABLE GGYU
+B044 ; LV # Lo HANGUL SYLLABLE GGEU
+B060 ; LV # Lo HANGUL SYLLABLE GGYI
+B07C ; LV # Lo HANGUL SYLLABLE GGI
+B098 ; LV # Lo HANGUL SYLLABLE NA
+B0B4 ; LV # Lo HANGUL SYLLABLE NAE
+B0D0 ; LV # Lo HANGUL SYLLABLE NYA
+B0EC ; LV # Lo HANGUL SYLLABLE NYAE
+B108 ; LV # Lo HANGUL SYLLABLE NEO
+B124 ; LV # Lo HANGUL SYLLABLE NE
+B140 ; LV # Lo HANGUL SYLLABLE NYEO
+B15C ; LV # Lo HANGUL SYLLABLE NYE
+B178 ; LV # Lo HANGUL SYLLABLE NO
+B194 ; LV # Lo HANGUL SYLLABLE NWA
+B1B0 ; LV # Lo HANGUL SYLLABLE NWAE
+B1CC ; LV # Lo HANGUL SYLLABLE NOE
+B1E8 ; LV # Lo HANGUL SYLLABLE NYO
+B204 ; LV # Lo HANGUL SYLLABLE NU
+B220 ; LV # Lo HANGUL SYLLABLE NWEO
+B23C ; LV # Lo HANGUL SYLLABLE NWE
+B258 ; LV # Lo HANGUL SYLLABLE NWI
+B274 ; LV # Lo HANGUL SYLLABLE NYU
+B290 ; LV # Lo HANGUL SYLLABLE NEU
+B2AC ; LV # Lo HANGUL SYLLABLE NYI
+B2C8 ; LV # Lo HANGUL SYLLABLE NI
+B2E4 ; LV # Lo HANGUL SYLLABLE DA
+B300 ; LV # Lo HANGUL SYLLABLE DAE
+B31C ; LV # Lo HANGUL SYLLABLE DYA
+B338 ; LV # Lo HANGUL SYLLABLE DYAE
+B354 ; LV # Lo HANGUL SYLLABLE DEO
+B370 ; LV # Lo HANGUL SYLLABLE DE
+B38C ; LV # Lo HANGUL SYLLABLE DYEO
+B3A8 ; LV # Lo HANGUL SYLLABLE DYE
+B3C4 ; LV # Lo HANGUL SYLLABLE DO
+B3E0 ; LV # Lo HANGUL SYLLABLE DWA
+B3FC ; LV # Lo HANGUL SYLLABLE DWAE
+B418 ; LV # Lo HANGUL SYLLABLE DOE
+B434 ; LV # Lo HANGUL SYLLABLE DYO
+B450 ; LV # Lo HANGUL SYLLABLE DU
+B46C ; LV # Lo HANGUL SYLLABLE DWEO
+B488 ; LV # Lo HANGUL SYLLABLE DWE
+B4A4 ; LV # Lo HANGUL SYLLABLE DWI
+B4C0 ; LV # Lo HANGUL SYLLABLE DYU
+B4DC ; LV # Lo HANGUL SYLLABLE DEU
+B4F8 ; LV # Lo HANGUL SYLLABLE DYI
+B514 ; LV # Lo HANGUL SYLLABLE DI
+B530 ; LV # Lo HANGUL SYLLABLE DDA
+B54C ; LV # Lo HANGUL SYLLABLE DDAE
+B568 ; LV # Lo HANGUL SYLLABLE DDYA
+B584 ; LV # Lo HANGUL SYLLABLE DDYAE
+B5A0 ; LV # Lo HANGUL SYLLABLE DDEO
+B5BC ; LV # Lo HANGUL SYLLABLE DDE
+B5D8 ; LV # Lo HANGUL SYLLABLE DDYEO
+B5F4 ; LV # Lo HANGUL SYLLABLE DDYE
+B610 ; LV # Lo HANGUL SYLLABLE DDO
+B62C ; LV # Lo HANGUL SYLLABLE DDWA
+B648 ; LV # Lo HANGUL SYLLABLE DDWAE
+B664 ; LV # Lo HANGUL SYLLABLE DDOE
+B680 ; LV # Lo HANGUL SYLLABLE DDYO
+B69C ; LV # Lo HANGUL SYLLABLE DDU
+B6B8 ; LV # Lo HANGUL SYLLABLE DDWEO
+B6D4 ; LV # Lo HANGUL SYLLABLE DDWE
+B6F0 ; LV # Lo HANGUL SYLLABLE DDWI
+B70C ; LV # Lo HANGUL SYLLABLE DDYU
+B728 ; LV # Lo HANGUL SYLLABLE DDEU
+B744 ; LV # Lo HANGUL SYLLABLE DDYI
+B760 ; LV # Lo HANGUL SYLLABLE DDI
+B77C ; LV # Lo HANGUL SYLLABLE RA
+B798 ; LV # Lo HANGUL SYLLABLE RAE
+B7B4 ; LV # Lo HANGUL SYLLABLE RYA
+B7D0 ; LV # Lo HANGUL SYLLABLE RYAE
+B7EC ; LV # Lo HANGUL SYLLABLE REO
+B808 ; LV # Lo HANGUL SYLLABLE RE
+B824 ; LV # Lo HANGUL SYLLABLE RYEO
+B840 ; LV # Lo HANGUL SYLLABLE RYE
+B85C ; LV # Lo HANGUL SYLLABLE RO
+B878 ; LV # Lo HANGUL SYLLABLE RWA
+B894 ; LV # Lo HANGUL SYLLABLE RWAE
+B8B0 ; LV # Lo HANGUL SYLLABLE ROE
+B8CC ; LV # Lo HANGUL SYLLABLE RYO
+B8E8 ; LV # Lo HANGUL SYLLABLE RU
+B904 ; LV # Lo HANGUL SYLLABLE RWEO
+B920 ; LV # Lo HANGUL SYLLABLE RWE
+B93C ; LV # Lo HANGUL SYLLABLE RWI
+B958 ; LV # Lo HANGUL SYLLABLE RYU
+B974 ; LV # Lo HANGUL SYLLABLE REU
+B990 ; LV # Lo HANGUL SYLLABLE RYI
+B9AC ; LV # Lo HANGUL SYLLABLE RI
+B9C8 ; LV # Lo HANGUL SYLLABLE MA
+B9E4 ; LV # Lo HANGUL SYLLABLE MAE
+BA00 ; LV # Lo HANGUL SYLLABLE MYA
+BA1C ; LV # Lo HANGUL SYLLABLE MYAE
+BA38 ; LV # Lo HANGUL SYLLABLE MEO
+BA54 ; LV # Lo HANGUL SYLLABLE ME
+BA70 ; LV # Lo HANGUL SYLLABLE MYEO
+BA8C ; LV # Lo HANGUL SYLLABLE MYE
+BAA8 ; LV # Lo HANGUL SYLLABLE MO
+BAC4 ; LV # Lo HANGUL SYLLABLE MWA
+BAE0 ; LV # Lo HANGUL SYLLABLE MWAE
+BAFC ; LV # Lo HANGUL SYLLABLE MOE
+BB18 ; LV # Lo HANGUL SYLLABLE MYO
+BB34 ; LV # Lo HANGUL SYLLABLE MU
+BB50 ; LV # Lo HANGUL SYLLABLE MWEO
+BB6C ; LV # Lo HANGUL SYLLABLE MWE
+BB88 ; LV # Lo HANGUL SYLLABLE MWI
+BBA4 ; LV # Lo HANGUL SYLLABLE MYU
+BBC0 ; LV # Lo HANGUL SYLLABLE MEU
+BBDC ; LV # Lo HANGUL SYLLABLE MYI
+BBF8 ; LV # Lo HANGUL SYLLABLE MI
+BC14 ; LV # Lo HANGUL SYLLABLE BA
+BC30 ; LV # Lo HANGUL SYLLABLE BAE
+BC4C ; LV # Lo HANGUL SYLLABLE BYA
+BC68 ; LV # Lo HANGUL SYLLABLE BYAE
+BC84 ; LV # Lo HANGUL SYLLABLE BEO
+BCA0 ; LV # Lo HANGUL SYLLABLE BE
+BCBC ; LV # Lo HANGUL SYLLABLE BYEO
+BCD8 ; LV # Lo HANGUL SYLLABLE BYE
+BCF4 ; LV # Lo HANGUL SYLLABLE BO
+BD10 ; LV # Lo HANGUL SYLLABLE BWA
+BD2C ; LV # Lo HANGUL SYLLABLE BWAE
+BD48 ; LV # Lo HANGUL SYLLABLE BOE
+BD64 ; LV # Lo HANGUL SYLLABLE BYO
+BD80 ; LV # Lo HANGUL SYLLABLE BU
+BD9C ; LV # Lo HANGUL SYLLABLE BWEO
+BDB8 ; LV # Lo HANGUL SYLLABLE BWE
+BDD4 ; LV # Lo HANGUL SYLLABLE BWI
+BDF0 ; LV # Lo HANGUL SYLLABLE BYU
+BE0C ; LV # Lo HANGUL SYLLABLE BEU
+BE28 ; LV # Lo HANGUL SYLLABLE BYI
+BE44 ; LV # Lo HANGUL SYLLABLE BI
+BE60 ; LV # Lo HANGUL SYLLABLE BBA
+BE7C ; LV # Lo HANGUL SYLLABLE BBAE
+BE98 ; LV # Lo HANGUL SYLLABLE BBYA
+BEB4 ; LV # Lo HANGUL SYLLABLE BBYAE
+BED0 ; LV # Lo HANGUL SYLLABLE BBEO
+BEEC ; LV # Lo HANGUL SYLLABLE BBE
+BF08 ; LV # Lo HANGUL SYLLABLE BBYEO
+BF24 ; LV # Lo HANGUL SYLLABLE BBYE
+BF40 ; LV # Lo HANGUL SYLLABLE BBO
+BF5C ; LV # Lo HANGUL SYLLABLE BBWA
+BF78 ; LV # Lo HANGUL SYLLABLE BBWAE
+BF94 ; LV # Lo HANGUL SYLLABLE BBOE
+BFB0 ; LV # Lo HANGUL SYLLABLE BBYO
+BFCC ; LV # Lo HANGUL SYLLABLE BBU
+BFE8 ; LV # Lo HANGUL SYLLABLE BBWEO
+C004 ; LV # Lo HANGUL SYLLABLE BBWE
+C020 ; LV # Lo HANGUL SYLLABLE BBWI
+C03C ; LV # Lo HANGUL SYLLABLE BBYU
+C058 ; LV # Lo HANGUL SYLLABLE BBEU
+C074 ; LV # Lo HANGUL SYLLABLE BBYI
+C090 ; LV # Lo HANGUL SYLLABLE BBI
+C0AC ; LV # Lo HANGUL SYLLABLE SA
+C0C8 ; LV # Lo HANGUL SYLLABLE SAE
+C0E4 ; LV # Lo HANGUL SYLLABLE SYA
+C100 ; LV # Lo HANGUL SYLLABLE SYAE
+C11C ; LV # Lo HANGUL SYLLABLE SEO
+C138 ; LV # Lo HANGUL SYLLABLE SE
+C154 ; LV # Lo HANGUL SYLLABLE SYEO
+C170 ; LV # Lo HANGUL SYLLABLE SYE
+C18C ; LV # Lo HANGUL SYLLABLE SO
+C1A8 ; LV # Lo HANGUL SYLLABLE SWA
+C1C4 ; LV # Lo HANGUL SYLLABLE SWAE
+C1E0 ; LV # Lo HANGUL SYLLABLE SOE
+C1FC ; LV # Lo HANGUL SYLLABLE SYO
+C218 ; LV # Lo HANGUL SYLLABLE SU
+C234 ; LV # Lo HANGUL SYLLABLE SWEO
+C250 ; LV # Lo HANGUL SYLLABLE SWE
+C26C ; LV # Lo HANGUL SYLLABLE SWI
+C288 ; LV # Lo HANGUL SYLLABLE SYU
+C2A4 ; LV # Lo HANGUL SYLLABLE SEU
+C2C0 ; LV # Lo HANGUL SYLLABLE SYI
+C2DC ; LV # Lo HANGUL SYLLABLE SI
+C2F8 ; LV # Lo HANGUL SYLLABLE SSA
+C314 ; LV # Lo HANGUL SYLLABLE SSAE
+C330 ; LV # Lo HANGUL SYLLABLE SSYA
+C34C ; LV # Lo HANGUL SYLLABLE SSYAE
+C368 ; LV # Lo HANGUL SYLLABLE SSEO
+C384 ; LV # Lo HANGUL SYLLABLE SSE
+C3A0 ; LV # Lo HANGUL SYLLABLE SSYEO
+C3BC ; LV # Lo HANGUL SYLLABLE SSYE
+C3D8 ; LV # Lo HANGUL SYLLABLE SSO
+C3F4 ; LV # Lo HANGUL SYLLABLE SSWA
+C410 ; LV # Lo HANGUL SYLLABLE SSWAE
+C42C ; LV # Lo HANGUL SYLLABLE SSOE
+C448 ; LV # Lo HANGUL SYLLABLE SSYO
+C464 ; LV # Lo HANGUL SYLLABLE SSU
+C480 ; LV # Lo HANGUL SYLLABLE SSWEO
+C49C ; LV # Lo HANGUL SYLLABLE SSWE
+C4B8 ; LV # Lo HANGUL SYLLABLE SSWI
+C4D4 ; LV # Lo HANGUL SYLLABLE SSYU
+C4F0 ; LV # Lo HANGUL SYLLABLE SSEU
+C50C ; LV # Lo HANGUL SYLLABLE SSYI
+C528 ; LV # Lo HANGUL SYLLABLE SSI
+C544 ; LV # Lo HANGUL SYLLABLE A
+C560 ; LV # Lo HANGUL SYLLABLE AE
+C57C ; LV # Lo HANGUL SYLLABLE YA
+C598 ; LV # Lo HANGUL SYLLABLE YAE
+C5B4 ; LV # Lo HANGUL SYLLABLE EO
+C5D0 ; LV # Lo HANGUL SYLLABLE E
+C5EC ; LV # Lo HANGUL SYLLABLE YEO
+C608 ; LV # Lo HANGUL SYLLABLE YE
+C624 ; LV # Lo HANGUL SYLLABLE O
+C640 ; LV # Lo HANGUL SYLLABLE WA
+C65C ; LV # Lo HANGUL SYLLABLE WAE
+C678 ; LV # Lo HANGUL SYLLABLE OE
+C694 ; LV # Lo HANGUL SYLLABLE YO
+C6B0 ; LV # Lo HANGUL SYLLABLE U
+C6CC ; LV # Lo HANGUL SYLLABLE WEO
+C6E8 ; LV # Lo HANGUL SYLLABLE WE
+C704 ; LV # Lo HANGUL SYLLABLE WI
+C720 ; LV # Lo HANGUL SYLLABLE YU
+C73C ; LV # Lo HANGUL SYLLABLE EU
+C758 ; LV # Lo HANGUL SYLLABLE YI
+C774 ; LV # Lo HANGUL SYLLABLE I
+C790 ; LV # Lo HANGUL SYLLABLE JA
+C7AC ; LV # Lo HANGUL SYLLABLE JAE
+C7C8 ; LV # Lo HANGUL SYLLABLE JYA
+C7E4 ; LV # Lo HANGUL SYLLABLE JYAE
+C800 ; LV # Lo HANGUL SYLLABLE JEO
+C81C ; LV # Lo HANGUL SYLLABLE JE
+C838 ; LV # Lo HANGUL SYLLABLE JYEO
+C854 ; LV # Lo HANGUL SYLLABLE JYE
+C870 ; LV # Lo HANGUL SYLLABLE JO
+C88C ; LV # Lo HANGUL SYLLABLE JWA
+C8A8 ; LV # Lo HANGUL SYLLABLE JWAE
+C8C4 ; LV # Lo HANGUL SYLLABLE JOE
+C8E0 ; LV # Lo HANGUL SYLLABLE JYO
+C8FC ; LV # Lo HANGUL SYLLABLE JU
+C918 ; LV # Lo HANGUL SYLLABLE JWEO
+C934 ; LV # Lo HANGUL SYLLABLE JWE
+C950 ; LV # Lo HANGUL SYLLABLE JWI
+C96C ; LV # Lo HANGUL SYLLABLE JYU
+C988 ; LV # Lo HANGUL SYLLABLE JEU
+C9A4 ; LV # Lo HANGUL SYLLABLE JYI
+C9C0 ; LV # Lo HANGUL SYLLABLE JI
+C9DC ; LV # Lo HANGUL SYLLABLE JJA
+C9F8 ; LV # Lo HANGUL SYLLABLE JJAE
+CA14 ; LV # Lo HANGUL SYLLABLE JJYA
+CA30 ; LV # Lo HANGUL SYLLABLE JJYAE
+CA4C ; LV # Lo HANGUL SYLLABLE JJEO
+CA68 ; LV # Lo HANGUL SYLLABLE JJE
+CA84 ; LV # Lo HANGUL SYLLABLE JJYEO
+CAA0 ; LV # Lo HANGUL SYLLABLE JJYE
+CABC ; LV # Lo HANGUL SYLLABLE JJO
+CAD8 ; LV # Lo HANGUL SYLLABLE JJWA
+CAF4 ; LV # Lo HANGUL SYLLABLE JJWAE
+CB10 ; LV # Lo HANGUL SYLLABLE JJOE
+CB2C ; LV # Lo HANGUL SYLLABLE JJYO
+CB48 ; LV # Lo HANGUL SYLLABLE JJU
+CB64 ; LV # Lo HANGUL SYLLABLE JJWEO
+CB80 ; LV # Lo HANGUL SYLLABLE JJWE
+CB9C ; LV # Lo HANGUL SYLLABLE JJWI
+CBB8 ; LV # Lo HANGUL SYLLABLE JJYU
+CBD4 ; LV # Lo HANGUL SYLLABLE JJEU
+CBF0 ; LV # Lo HANGUL SYLLABLE JJYI
+CC0C ; LV # Lo HANGUL SYLLABLE JJI
+CC28 ; LV # Lo HANGUL SYLLABLE CA
+CC44 ; LV # Lo HANGUL SYLLABLE CAE
+CC60 ; LV # Lo HANGUL SYLLABLE CYA
+CC7C ; LV # Lo HANGUL SYLLABLE CYAE
+CC98 ; LV # Lo HANGUL SYLLABLE CEO
+CCB4 ; LV # Lo HANGUL SYLLABLE CE
+CCD0 ; LV # Lo HANGUL SYLLABLE CYEO
+CCEC ; LV # Lo HANGUL SYLLABLE CYE
+CD08 ; LV # Lo HANGUL SYLLABLE CO
+CD24 ; LV # Lo HANGUL SYLLABLE CWA
+CD40 ; LV # Lo HANGUL SYLLABLE CWAE
+CD5C ; LV # Lo HANGUL SYLLABLE COE
+CD78 ; LV # Lo HANGUL SYLLABLE CYO
+CD94 ; LV # Lo HANGUL SYLLABLE CU
+CDB0 ; LV # Lo HANGUL SYLLABLE CWEO
+CDCC ; LV # Lo HANGUL SYLLABLE CWE
+CDE8 ; LV # Lo HANGUL SYLLABLE CWI
+CE04 ; LV # Lo HANGUL SYLLABLE CYU
+CE20 ; LV # Lo HANGUL SYLLABLE CEU
+CE3C ; LV # Lo HANGUL SYLLABLE CYI
+CE58 ; LV # Lo HANGUL SYLLABLE CI
+CE74 ; LV # Lo HANGUL SYLLABLE KA
+CE90 ; LV # Lo HANGUL SYLLABLE KAE
+CEAC ; LV # Lo HANGUL SYLLABLE KYA
+CEC8 ; LV # Lo HANGUL SYLLABLE KYAE
+CEE4 ; LV # Lo HANGUL SYLLABLE KEO
+CF00 ; LV # Lo HANGUL SYLLABLE KE
+CF1C ; LV # Lo HANGUL SYLLABLE KYEO
+CF38 ; LV # Lo HANGUL SYLLABLE KYE
+CF54 ; LV # Lo HANGUL SYLLABLE KO
+CF70 ; LV # Lo HANGUL SYLLABLE KWA
+CF8C ; LV # Lo HANGUL SYLLABLE KWAE
+CFA8 ; LV # Lo HANGUL SYLLABLE KOE
+CFC4 ; LV # Lo HANGUL SYLLABLE KYO
+CFE0 ; LV # Lo HANGUL SYLLABLE KU
+CFFC ; LV # Lo HANGUL SYLLABLE KWEO
+D018 ; LV # Lo HANGUL SYLLABLE KWE
+D034 ; LV # Lo HANGUL SYLLABLE KWI
+D050 ; LV # Lo HANGUL SYLLABLE KYU
+D06C ; LV # Lo HANGUL SYLLABLE KEU
+D088 ; LV # Lo HANGUL SYLLABLE KYI
+D0A4 ; LV # Lo HANGUL SYLLABLE KI
+D0C0 ; LV # Lo HANGUL SYLLABLE TA
+D0DC ; LV # Lo HANGUL SYLLABLE TAE
+D0F8 ; LV # Lo HANGUL SYLLABLE TYA
+D114 ; LV # Lo HANGUL SYLLABLE TYAE
+D130 ; LV # Lo HANGUL SYLLABLE TEO
+D14C ; LV # Lo HANGUL SYLLABLE TE
+D168 ; LV # Lo HANGUL SYLLABLE TYEO
+D184 ; LV # Lo HANGUL SYLLABLE TYE
+D1A0 ; LV # Lo HANGUL SYLLABLE TO
+D1BC ; LV # Lo HANGUL SYLLABLE TWA
+D1D8 ; LV # Lo HANGUL SYLLABLE TWAE
+D1F4 ; LV # Lo HANGUL SYLLABLE TOE
+D210 ; LV # Lo HANGUL SYLLABLE TYO
+D22C ; LV # Lo HANGUL SYLLABLE TU
+D248 ; LV # Lo HANGUL SYLLABLE TWEO
+D264 ; LV # Lo HANGUL SYLLABLE TWE
+D280 ; LV # Lo HANGUL SYLLABLE TWI
+D29C ; LV # Lo HANGUL SYLLABLE TYU
+D2B8 ; LV # Lo HANGUL SYLLABLE TEU
+D2D4 ; LV # Lo HANGUL SYLLABLE TYI
+D2F0 ; LV # Lo HANGUL SYLLABLE TI
+D30C ; LV # Lo HANGUL SYLLABLE PA
+D328 ; LV # Lo HANGUL SYLLABLE PAE
+D344 ; LV # Lo HANGUL SYLLABLE PYA
+D360 ; LV # Lo HANGUL SYLLABLE PYAE
+D37C ; LV # Lo HANGUL SYLLABLE PEO
+D398 ; LV # Lo HANGUL SYLLABLE PE
+D3B4 ; LV # Lo HANGUL SYLLABLE PYEO
+D3D0 ; LV # Lo HANGUL SYLLABLE PYE
+D3EC ; LV # Lo HANGUL SYLLABLE PO
+D408 ; LV # Lo HANGUL SYLLABLE PWA
+D424 ; LV # Lo HANGUL SYLLABLE PWAE
+D440 ; LV # Lo HANGUL SYLLABLE POE
+D45C ; LV # Lo HANGUL SYLLABLE PYO
+D478 ; LV # Lo HANGUL SYLLABLE PU
+D494 ; LV # Lo HANGUL SYLLABLE PWEO
+D4B0 ; LV # Lo HANGUL SYLLABLE PWE
+D4CC ; LV # Lo HANGUL SYLLABLE PWI
+D4E8 ; LV # Lo HANGUL SYLLABLE PYU
+D504 ; LV # Lo HANGUL SYLLABLE PEU
+D520 ; LV # Lo HANGUL SYLLABLE PYI
+D53C ; LV # Lo HANGUL SYLLABLE PI
+D558 ; LV # Lo HANGUL SYLLABLE HA
+D574 ; LV # Lo HANGUL SYLLABLE HAE
+D590 ; LV # Lo HANGUL SYLLABLE HYA
+D5AC ; LV # Lo HANGUL SYLLABLE HYAE
+D5C8 ; LV # Lo HANGUL SYLLABLE HEO
+D5E4 ; LV # Lo HANGUL SYLLABLE HE
+D600 ; LV # Lo HANGUL SYLLABLE HYEO
+D61C ; LV # Lo HANGUL SYLLABLE HYE
+D638 ; LV # Lo HANGUL SYLLABLE HO
+D654 ; LV # Lo HANGUL SYLLABLE HWA
+D670 ; LV # Lo HANGUL SYLLABLE HWAE
+D68C ; LV # Lo HANGUL SYLLABLE HOE
+D6A8 ; LV # Lo HANGUL SYLLABLE HYO
+D6C4 ; LV # Lo HANGUL SYLLABLE HU
+D6E0 ; LV # Lo HANGUL SYLLABLE HWEO
+D6FC ; LV # Lo HANGUL SYLLABLE HWE
+D718 ; LV # Lo HANGUL SYLLABLE HWI
+D734 ; LV # Lo HANGUL SYLLABLE HYU
+D750 ; LV # Lo HANGUL SYLLABLE HEU
+D76C ; LV # Lo HANGUL SYLLABLE HYI
+D788 ; LV # Lo HANGUL SYLLABLE HI
+
+# Total code points: 399
+
+# ================================================
+
+AC01..AC1B ; LVT # Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH
+AC1D..AC37 ; LVT # Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH
+AC39..AC53 ; LVT # Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH
+AC55..AC6F ; LVT # Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH
+AC71..AC8B ; LVT # Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH
+AC8D..ACA7 ; LVT # Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH
+ACA9..ACC3 ; LVT # Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH
+ACC5..ACDF ; LVT # Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH
+ACE1..ACFB ; LVT # Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH
+ACFD..AD17 ; LVT # Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH
+AD19..AD33 ; LVT # Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH
+AD35..AD4F ; LVT # Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH
+AD51..AD6B ; LVT # Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH
+AD6D..AD87 ; LVT # Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH
+AD89..ADA3 ; LVT # Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH
+ADA5..ADBF ; LVT # Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH
+ADC1..ADDB ; LVT # Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH
+ADDD..ADF7 ; LVT # Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH
+ADF9..AE13 ; LVT # Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH
+AE15..AE2F ; LVT # Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH
+AE31..AE4B ; LVT # Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH
+AE4D..AE67 ; LVT # Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH
+AE69..AE83 ; LVT # Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH
+AE85..AE9F ; LVT # Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH
+AEA1..AEBB ; LVT # Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH
+AEBD..AED7 ; LVT # Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH
+AED9..AEF3 ; LVT # Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH
+AEF5..AF0F ; LVT # Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH
+AF11..AF2B ; LVT # Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH
+AF2D..AF47 ; LVT # Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH
+AF49..AF63 ; LVT # Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH
+AF65..AF7F ; LVT # Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH
+AF81..AF9B ; LVT # Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH
+AF9D..AFB7 ; LVT # Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH
+AFB9..AFD3 ; LVT # Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH
+AFD5..AFEF ; LVT # Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH
+AFF1..B00B ; LVT # Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH
+B00D..B027 ; LVT # Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH
+B029..B043 ; LVT # Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH
+B045..B05F ; LVT # Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH
+B061..B07B ; LVT # Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH
+B07D..B097 ; LVT # Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH
+B099..B0B3 ; LVT # Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH
+B0B5..B0CF ; LVT # Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH
+B0D1..B0EB ; LVT # Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH
+B0ED..B107 ; LVT # Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH
+B109..B123 ; LVT # Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH
+B125..B13F ; LVT # Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH
+B141..B15B ; LVT # Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH
+B15D..B177 ; LVT # Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH
+B179..B193 ; LVT # Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH
+B195..B1AF ; LVT # Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH
+B1B1..B1CB ; LVT # Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH
+B1CD..B1E7 ; LVT # Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH
+B1E9..B203 ; LVT # Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH
+B205..B21F ; LVT # Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH
+B221..B23B ; LVT # Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH
+B23D..B257 ; LVT # Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH
+B259..B273 ; LVT # Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH
+B275..B28F ; LVT # Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH
+B291..B2AB ; LVT # Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH
+B2AD..B2C7 ; LVT # Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH
+B2C9..B2E3 ; LVT # Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH
+B2E5..B2FF ; LVT # Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH
+B301..B31B ; LVT # Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH
+B31D..B337 ; LVT # Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH
+B339..B353 ; LVT # Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH
+B355..B36F ; LVT # Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH
+B371..B38B ; LVT # Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH
+B38D..B3A7 ; LVT # Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH
+B3A9..B3C3 ; LVT # Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH
+B3C5..B3DF ; LVT # Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH
+B3E1..B3FB ; LVT # Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH
+B3FD..B417 ; LVT # Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH
+B419..B433 ; LVT # Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH
+B435..B44F ; LVT # Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH
+B451..B46B ; LVT # Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH
+B46D..B487 ; LVT # Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH
+B489..B4A3 ; LVT # Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH
+B4A5..B4BF ; LVT # Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH
+B4C1..B4DB ; LVT # Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH
+B4DD..B4F7 ; LVT # Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH
+B4F9..B513 ; LVT # Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH
+B515..B52F ; LVT # Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH
+B531..B54B ; LVT # Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH
+B54D..B567 ; LVT # Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH
+B569..B583 ; LVT # Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH
+B585..B59F ; LVT # Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH
+B5A1..B5BB ; LVT # Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH
+B5BD..B5D7 ; LVT # Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH
+B5D9..B5F3 ; LVT # Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH
+B5F5..B60F ; LVT # Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH
+B611..B62B ; LVT # Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH
+B62D..B647 ; LVT # Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH
+B649..B663 ; LVT # Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH
+B665..B67F ; LVT # Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH
+B681..B69B ; LVT # Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH
+B69D..B6B7 ; LVT # Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH
+B6B9..B6D3 ; LVT # Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH
+B6D5..B6EF ; LVT # Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH
+B6F1..B70B ; LVT # Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH
+B70D..B727 ; LVT # Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH
+B729..B743 ; LVT # Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH
+B745..B75F ; LVT # Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH
+B761..B77B ; LVT # Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH
+B77D..B797 ; LVT # Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH
+B799..B7B3 ; LVT # Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH
+B7B5..B7CF ; LVT # Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH
+B7D1..B7EB ; LVT # Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH
+B7ED..B807 ; LVT # Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH
+B809..B823 ; LVT # Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH
+B825..B83F ; LVT # Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH
+B841..B85B ; LVT # Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH
+B85D..B877 ; LVT # Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH
+B879..B893 ; LVT # Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH
+B895..B8AF ; LVT # Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH
+B8B1..B8CB ; LVT # Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH
+B8CD..B8E7 ; LVT # Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH
+B8E9..B903 ; LVT # Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH
+B905..B91F ; LVT # Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH
+B921..B93B ; LVT # Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH
+B93D..B957 ; LVT # Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH
+B959..B973 ; LVT # Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH
+B975..B98F ; LVT # Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH
+B991..B9AB ; LVT # Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH
+B9AD..B9C7 ; LVT # Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH
+B9C9..B9E3 ; LVT # Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH
+B9E5..B9FF ; LVT # Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH
+BA01..BA1B ; LVT # Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH
+BA1D..BA37 ; LVT # Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH
+BA39..BA53 ; LVT # Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH
+BA55..BA6F ; LVT # Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH
+BA71..BA8B ; LVT # Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH
+BA8D..BAA7 ; LVT # Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH
+BAA9..BAC3 ; LVT # Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH
+BAC5..BADF ; LVT # Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH
+BAE1..BAFB ; LVT # Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH
+BAFD..BB17 ; LVT # Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH
+BB19..BB33 ; LVT # Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH
+BB35..BB4F ; LVT # Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH
+BB51..BB6B ; LVT # Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH
+BB6D..BB87 ; LVT # Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH
+BB89..BBA3 ; LVT # Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH
+BBA5..BBBF ; LVT # Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH
+BBC1..BBDB ; LVT # Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH
+BBDD..BBF7 ; LVT # Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH
+BBF9..BC13 ; LVT # Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH
+BC15..BC2F ; LVT # Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH
+BC31..BC4B ; LVT # Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH
+BC4D..BC67 ; LVT # Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH
+BC69..BC83 ; LVT # Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH
+BC85..BC9F ; LVT # Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH
+BCA1..BCBB ; LVT # Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH
+BCBD..BCD7 ; LVT # Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH
+BCD9..BCF3 ; LVT # Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH
+BCF5..BD0F ; LVT # Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH
+BD11..BD2B ; LVT # Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH
+BD2D..BD47 ; LVT # Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH
+BD49..BD63 ; LVT # Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH
+BD65..BD7F ; LVT # Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH
+BD81..BD9B ; LVT # Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH
+BD9D..BDB7 ; LVT # Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH
+BDB9..BDD3 ; LVT # Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH
+BDD5..BDEF ; LVT # Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH
+BDF1..BE0B ; LVT # Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH
+BE0D..BE27 ; LVT # Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH
+BE29..BE43 ; LVT # Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH
+BE45..BE5F ; LVT # Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH
+BE61..BE7B ; LVT # Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH
+BE7D..BE97 ; LVT # Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH
+BE99..BEB3 ; LVT # Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH
+BEB5..BECF ; LVT # Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH
+BED1..BEEB ; LVT # Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH
+BEED..BF07 ; LVT # Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH
+BF09..BF23 ; LVT # Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH
+BF25..BF3F ; LVT # Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH
+BF41..BF5B ; LVT # Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH
+BF5D..BF77 ; LVT # Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH
+BF79..BF93 ; LVT # Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH
+BF95..BFAF ; LVT # Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH
+BFB1..BFCB ; LVT # Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH
+BFCD..BFE7 ; LVT # Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH
+BFE9..C003 ; LVT # Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH
+C005..C01F ; LVT # Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH
+C021..C03B ; LVT # Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH
+C03D..C057 ; LVT # Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH
+C059..C073 ; LVT # Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH
+C075..C08F ; LVT # Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH
+C091..C0AB ; LVT # Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH
+C0AD..C0C7 ; LVT # Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH
+C0C9..C0E3 ; LVT # Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH
+C0E5..C0FF ; LVT # Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH
+C101..C11B ; LVT # Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH
+C11D..C137 ; LVT # Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH
+C139..C153 ; LVT # Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH
+C155..C16F ; LVT # Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH
+C171..C18B ; LVT # Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH
+C18D..C1A7 ; LVT # Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH
+C1A9..C1C3 ; LVT # Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH
+C1C5..C1DF ; LVT # Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH
+C1E1..C1FB ; LVT # Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH
+C1FD..C217 ; LVT # Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH
+C219..C233 ; LVT # Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH
+C235..C24F ; LVT # Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH
+C251..C26B ; LVT # Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH
+C26D..C287 ; LVT # Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH
+C289..C2A3 ; LVT # Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH
+C2A5..C2BF ; LVT # Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH
+C2C1..C2DB ; LVT # Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH
+C2DD..C2F7 ; LVT # Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH
+C2F9..C313 ; LVT # Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH
+C315..C32F ; LVT # Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH
+C331..C34B ; LVT # Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH
+C34D..C367 ; LVT # Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH
+C369..C383 ; LVT # Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH
+C385..C39F ; LVT # Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH
+C3A1..C3BB ; LVT # Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH
+C3BD..C3D7 ; LVT # Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH
+C3D9..C3F3 ; LVT # Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH
+C3F5..C40F ; LVT # Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH
+C411..C42B ; LVT # Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH
+C42D..C447 ; LVT # Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH
+C449..C463 ; LVT # Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH
+C465..C47F ; LVT # Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH
+C481..C49B ; LVT # Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH
+C49D..C4B7 ; LVT # Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH
+C4B9..C4D3 ; LVT # Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH
+C4D5..C4EF ; LVT # Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH
+C4F1..C50B ; LVT # Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH
+C50D..C527 ; LVT # Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH
+C529..C543 ; LVT # Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH
+C545..C55F ; LVT # Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH
+C561..C57B ; LVT # Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH
+C57D..C597 ; LVT # Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH
+C599..C5B3 ; LVT # Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH
+C5B5..C5CF ; LVT # Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH
+C5D1..C5EB ; LVT # Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH
+C5ED..C607 ; LVT # Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH
+C609..C623 ; LVT # Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH
+C625..C63F ; LVT # Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH
+C641..C65B ; LVT # Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH
+C65D..C677 ; LVT # Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH
+C679..C693 ; LVT # Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH
+C695..C6AF ; LVT # Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH
+C6B1..C6CB ; LVT # Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH
+C6CD..C6E7 ; LVT # Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH
+C6E9..C703 ; LVT # Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH
+C705..C71F ; LVT # Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH
+C721..C73B ; LVT # Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH
+C73D..C757 ; LVT # Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH
+C759..C773 ; LVT # Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH
+C775..C78F ; LVT # Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH
+C791..C7AB ; LVT # Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH
+C7AD..C7C7 ; LVT # Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH
+C7C9..C7E3 ; LVT # Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH
+C7E5..C7FF ; LVT # Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH
+C801..C81B ; LVT # Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH
+C81D..C837 ; LVT # Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH
+C839..C853 ; LVT # Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH
+C855..C86F ; LVT # Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH
+C871..C88B ; LVT # Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH
+C88D..C8A7 ; LVT # Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH
+C8A9..C8C3 ; LVT # Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH
+C8C5..C8DF ; LVT # Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH
+C8E1..C8FB ; LVT # Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH
+C8FD..C917 ; LVT # Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH
+C919..C933 ; LVT # Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH
+C935..C94F ; LVT # Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH
+C951..C96B ; LVT # Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH
+C96D..C987 ; LVT # Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH
+C989..C9A3 ; LVT # Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH
+C9A5..C9BF ; LVT # Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH
+C9C1..C9DB ; LVT # Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH
+C9DD..C9F7 ; LVT # Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH
+C9F9..CA13 ; LVT # Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH
+CA15..CA2F ; LVT # Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH
+CA31..CA4B ; LVT # Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH
+CA4D..CA67 ; LVT # Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH
+CA69..CA83 ; LVT # Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH
+CA85..CA9F ; LVT # Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH
+CAA1..CABB ; LVT # Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH
+CABD..CAD7 ; LVT # Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH
+CAD9..CAF3 ; LVT # Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH
+CAF5..CB0F ; LVT # Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH
+CB11..CB2B ; LVT # Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH
+CB2D..CB47 ; LVT # Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH
+CB49..CB63 ; LVT # Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH
+CB65..CB7F ; LVT # Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH
+CB81..CB9B ; LVT # Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH
+CB9D..CBB7 ; LVT # Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH
+CBB9..CBD3 ; LVT # Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH
+CBD5..CBEF ; LVT # Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH
+CBF1..CC0B ; LVT # Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH
+CC0D..CC27 ; LVT # Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH
+CC29..CC43 ; LVT # Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH
+CC45..CC5F ; LVT # Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH
+CC61..CC7B ; LVT # Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH
+CC7D..CC97 ; LVT # Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH
+CC99..CCB3 ; LVT # Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH
+CCB5..CCCF ; LVT # Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH
+CCD1..CCEB ; LVT # Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH
+CCED..CD07 ; LVT # Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH
+CD09..CD23 ; LVT # Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH
+CD25..CD3F ; LVT # Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH
+CD41..CD5B ; LVT # Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH
+CD5D..CD77 ; LVT # Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH
+CD79..CD93 ; LVT # Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH
+CD95..CDAF ; LVT # Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH
+CDB1..CDCB ; LVT # Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH
+CDCD..CDE7 ; LVT # Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH
+CDE9..CE03 ; LVT # Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH
+CE05..CE1F ; LVT # Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH
+CE21..CE3B ; LVT # Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH
+CE3D..CE57 ; LVT # Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH
+CE59..CE73 ; LVT # Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH
+CE75..CE8F ; LVT # Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH
+CE91..CEAB ; LVT # Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH
+CEAD..CEC7 ; LVT # Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH
+CEC9..CEE3 ; LVT # Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH
+CEE5..CEFF ; LVT # Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH
+CF01..CF1B ; LVT # Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH
+CF1D..CF37 ; LVT # Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH
+CF39..CF53 ; LVT # Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH
+CF55..CF6F ; LVT # Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH
+CF71..CF8B ; LVT # Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH
+CF8D..CFA7 ; LVT # Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH
+CFA9..CFC3 ; LVT # Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH
+CFC5..CFDF ; LVT # Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH
+CFE1..CFFB ; LVT # Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH
+CFFD..D017 ; LVT # Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH
+D019..D033 ; LVT # Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH
+D035..D04F ; LVT # Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH
+D051..D06B ; LVT # Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH
+D06D..D087 ; LVT # Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH
+D089..D0A3 ; LVT # Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH
+D0A5..D0BF ; LVT # Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH
+D0C1..D0DB ; LVT # Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH
+D0DD..D0F7 ; LVT # Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH
+D0F9..D113 ; LVT # Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH
+D115..D12F ; LVT # Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH
+D131..D14B ; LVT # Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH
+D14D..D167 ; LVT # Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH
+D169..D183 ; LVT # Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH
+D185..D19F ; LVT # Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH
+D1A1..D1BB ; LVT # Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH
+D1BD..D1D7 ; LVT # Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH
+D1D9..D1F3 ; LVT # Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH
+D1F5..D20F ; LVT # Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH
+D211..D22B ; LVT # Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH
+D22D..D247 ; LVT # Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH
+D249..D263 ; LVT # Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH
+D265..D27F ; LVT # Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH
+D281..D29B ; LVT # Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH
+D29D..D2B7 ; LVT # Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH
+D2B9..D2D3 ; LVT # Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH
+D2D5..D2EF ; LVT # Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH
+D2F1..D30B ; LVT # Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH
+D30D..D327 ; LVT # Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH
+D329..D343 ; LVT # Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH
+D345..D35F ; LVT # Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH
+D361..D37B ; LVT # Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH
+D37D..D397 ; LVT # Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH
+D399..D3B3 ; LVT # Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH
+D3B5..D3CF ; LVT # Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH
+D3D1..D3EB ; LVT # Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH
+D3ED..D407 ; LVT # Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH
+D409..D423 ; LVT # Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH
+D425..D43F ; LVT # Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH
+D441..D45B ; LVT # Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH
+D45D..D477 ; LVT # Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH
+D479..D493 ; LVT # Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH
+D495..D4AF ; LVT # Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH
+D4B1..D4CB ; LVT # Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH
+D4CD..D4E7 ; LVT # Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH
+D4E9..D503 ; LVT # Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH
+D505..D51F ; LVT # Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH
+D521..D53B ; LVT # Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH
+D53D..D557 ; LVT # Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH
+D559..D573 ; LVT # Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH
+D575..D58F ; LVT # Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH
+D591..D5AB ; LVT # Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH
+D5AD..D5C7 ; LVT # Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH
+D5C9..D5E3 ; LVT # Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH
+D5E5..D5FF ; LVT # Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH
+D601..D61B ; LVT # Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH
+D61D..D637 ; LVT # Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH
+D639..D653 ; LVT # Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH
+D655..D66F ; LVT # Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH
+D671..D68B ; LVT # Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH
+D68D..D6A7 ; LVT # Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH
+D6A9..D6C3 ; LVT # Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH
+D6C5..D6DF ; LVT # Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH
+D6E1..D6FB ; LVT # Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH
+D6FD..D717 ; LVT # Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH
+D719..D733 ; LVT # Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH
+D735..D74F ; LVT # Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH
+D751..D76B ; LVT # Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH
+D76D..D787 ; LVT # Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH
+D789..D7A3 ; LVT # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
+
+# Total code points: 10773
+
+# EOF
diff --git a/third_party/harfbuzz/contrib/tables/README b/third_party/harfbuzz/contrib/tables/README
new file mode 100644
index 0000000..605d1c0
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/README
@@ -0,0 +1,17 @@
+This directory contains Python script to parse several of the Unicode tables
+that are downloadable from the web and generate C header files from them.
+
+These are the locations of the files which are parsed. You should download these
+files and put them in this directory.
+
+http://www.unicode.org/Public/5.1.0/ucd/extracted/DerivedGeneralCategory.txt
+http://www.unicode.org/Public/5.1.0/ucd/extracted/DerivedCombiningClass.txt
+http://www.unicode.org/Public/UNIDATA/auxiliary/GraphemeBreakProperty.txt
+http://www.unicode.org/Public/5.1.0/ucd/Scripts.txt
+
+Then you can run the following python scripts to generate the header files:
+
+python category-parse.py DerivedGeneralCategory.txt category-properties.h
+python combining-class-parse.py DerivedCombiningClass.txt combining-properties.h
+python grapheme-break-parse.py GraphemeBreakProperty.txt grapheme-break-properties.h
+python scripts-parse.py Scripts.txt script-properties.h
diff --git a/third_party/harfbuzz/contrib/tables/Scripts.txt b/third_party/harfbuzz/contrib/tables/Scripts.txt
new file mode 100644
index 0000000..7065486
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/Scripts.txt
@@ -0,0 +1,1747 @@
+# Scripts-5.1.0.txt
+# Date: 2008-03-20, 17:55:33 GMT [MD]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2008 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+
+# ================================================
+
+# Property: Script
+
+# All code points not explicitly listed for Script
+# have the value Unknown (Zzzz).
+
+# @missing: 0000..10FFFF; Unknown
+
+# ================================================
+
+0000..001F ; Common # Cc [32] <control-0000>..<control-001F>
+0020 ; Common # Zs SPACE
+0021..0023 ; Common # Po [3] EXCLAMATION MARK..NUMBER SIGN
+0024 ; Common # Sc DOLLAR SIGN
+0025..0027 ; Common # Po [3] PERCENT SIGN..APOSTROPHE
+0028 ; Common # Ps LEFT PARENTHESIS
+0029 ; Common # Pe RIGHT PARENTHESIS
+002A ; Common # Po ASTERISK
+002B ; Common # Sm PLUS SIGN
+002C ; Common # Po COMMA
+002D ; Common # Pd HYPHEN-MINUS
+002E..002F ; Common # Po [2] FULL STOP..SOLIDUS
+0030..0039 ; Common # Nd [10] DIGIT ZERO..DIGIT NINE
+003A..003B ; Common # Po [2] COLON..SEMICOLON
+003C..003E ; Common # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN
+003F..0040 ; Common # Po [2] QUESTION MARK..COMMERCIAL AT
+005B ; Common # Ps LEFT SQUARE BRACKET
+005C ; Common # Po REVERSE SOLIDUS
+005D ; Common # Pe RIGHT SQUARE BRACKET
+005E ; Common # Sk CIRCUMFLEX ACCENT
+005F ; Common # Pc LOW LINE
+0060 ; Common # Sk GRAVE ACCENT
+007B ; Common # Ps LEFT CURLY BRACKET
+007C ; Common # Sm VERTICAL LINE
+007D ; Common # Pe RIGHT CURLY BRACKET
+007E ; Common # Sm TILDE
+007F..009F ; Common # Cc [33] <control-007F>..<control-009F>
+00A0 ; Common # Zs NO-BREAK SPACE
+00A1 ; Common # Po INVERTED EXCLAMATION MARK
+00A2..00A5 ; Common # Sc [4] CENT SIGN..YEN SIGN
+00A6..00A7 ; Common # So [2] BROKEN BAR..SECTION SIGN
+00A8 ; Common # Sk DIAERESIS
+00A9 ; Common # So COPYRIGHT SIGN
+00AB ; Common # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+00AC ; Common # Sm NOT SIGN
+00AD ; Common # Cf SOFT HYPHEN
+00AE ; Common # So REGISTERED SIGN
+00AF ; Common # Sk MACRON
+00B0 ; Common # So DEGREE SIGN
+00B1 ; Common # Sm PLUS-MINUS SIGN
+00B2..00B3 ; Common # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE
+00B4 ; Common # Sk ACUTE ACCENT
+00B5 ; Common # L& MICRO SIGN
+00B6 ; Common # So PILCROW SIGN
+00B7 ; Common # Po MIDDLE DOT
+00B8 ; Common # Sk CEDILLA
+00B9 ; Common # No SUPERSCRIPT ONE
+00BB ; Common # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+00BC..00BE ; Common # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS
+00BF ; Common # Po INVERTED QUESTION MARK
+00D7 ; Common # Sm MULTIPLICATION SIGN
+00F7 ; Common # Sm DIVISION SIGN
+02B9..02C1 ; Common # Lm [9] MODIFIER LETTER PRIME..MODIFIER LETTER REVERSED GLOTTAL STOP
+02C2..02C5 ; Common # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
+02C6..02D1 ; Common # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
+02D2..02DF ; Common # Sk [14] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER CROSS ACCENT
+02E5..02EB ; Common # Sk [7] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER YANG DEPARTING TONE MARK
+02EC ; Common # Lm MODIFIER LETTER VOICING
+02ED ; Common # Sk MODIFIER LETTER UNASPIRATED
+02EE ; Common # Lm MODIFIER LETTER DOUBLE APOSTROPHE
+02EF..02FF ; Common # Sk [17] MODIFIER LETTER LOW DOWN ARROWHEAD..MODIFIER LETTER LOW LEFT ARROW
+0374 ; Common # Lm GREEK NUMERAL SIGN
+037E ; Common # Po GREEK QUESTION MARK
+0385 ; Common # Sk GREEK DIALYTIKA TONOS
+0387 ; Common # Po GREEK ANO TELEIA
+0589 ; Common # Po ARMENIAN FULL STOP
+0600..0603 ; Common # Cf [4] ARABIC NUMBER SIGN..ARABIC SIGN SAFHA
+060C ; Common # Po ARABIC COMMA
+061B ; Common # Po ARABIC SEMICOLON
+061F ; Common # Po ARABIC QUESTION MARK
+0640 ; Common # Lm ARABIC TATWEEL
+0660..0669 ; Common # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
+06DD ; Common # Cf ARABIC END OF AYAH
+0964..0965 ; Common # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
+0970 ; Common # Po DEVANAGARI ABBREVIATION SIGN
+0CF1..0CF2 ; Common # So [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
+0E3F ; Common # Sc THAI CURRENCY SYMBOL BAHT
+10FB ; Common # Po GEORGIAN PARAGRAPH SEPARATOR
+16EB..16ED ; Common # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
+1735..1736 ; Common # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
+1802..1803 ; Common # Po [2] MONGOLIAN COMMA..MONGOLIAN FULL STOP
+1805 ; Common # Po MONGOLIAN FOUR DOTS
+2000..200A ; Common # Zs [11] EN QUAD..HAIR SPACE
+200B ; Common # Cf ZERO WIDTH SPACE
+200E..200F ; Common # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
+2010..2015 ; Common # Pd [6] HYPHEN..HORIZONTAL BAR
+2016..2017 ; Common # Po [2] DOUBLE VERTICAL LINE..DOUBLE LOW LINE
+2018 ; Common # Pi LEFT SINGLE QUOTATION MARK
+2019 ; Common # Pf RIGHT SINGLE QUOTATION MARK
+201A ; Common # Ps SINGLE LOW-9 QUOTATION MARK
+201B..201C ; Common # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK
+201D ; Common # Pf RIGHT DOUBLE QUOTATION MARK
+201E ; Common # Ps DOUBLE LOW-9 QUOTATION MARK
+201F ; Common # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
+2020..2027 ; Common # Po [8] DAGGER..HYPHENATION POINT
+2028 ; Common # Zl LINE SEPARATOR
+2029 ; Common # Zp PARAGRAPH SEPARATOR
+202A..202E ; Common # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+202F ; Common # Zs NARROW NO-BREAK SPACE
+2030..2038 ; Common # Po [9] PER MILLE SIGN..CARET
+2039 ; Common # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+203A ; Common # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+203B..203E ; Common # Po [4] REFERENCE MARK..OVERLINE
+203F..2040 ; Common # Pc [2] UNDERTIE..CHARACTER TIE
+2041..2043 ; Common # Po [3] CARET INSERTION POINT..HYPHEN BULLET
+2044 ; Common # Sm FRACTION SLASH
+2045 ; Common # Ps LEFT SQUARE BRACKET WITH QUILL
+2046 ; Common # Pe RIGHT SQUARE BRACKET WITH QUILL
+2047..2051 ; Common # Po [11] DOUBLE QUESTION MARK..TWO ASTERISKS ALIGNED VERTICALLY
+2052 ; Common # Sm COMMERCIAL MINUS SIGN
+2053 ; Common # Po SWUNG DASH
+2054 ; Common # Pc INVERTED UNDERTIE
+2055..205E ; Common # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
+205F ; Common # Zs MEDIUM MATHEMATICAL SPACE
+2060..2064 ; Common # Cf [5] WORD JOINER..INVISIBLE PLUS
+206A..206F ; Common # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES
+2070 ; Common # No SUPERSCRIPT ZERO
+2074..2079 ; Common # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE
+207A..207C ; Common # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
+207D ; Common # Ps SUPERSCRIPT LEFT PARENTHESIS
+207E ; Common # Pe SUPERSCRIPT RIGHT PARENTHESIS
+2080..2089 ; Common # No [10] SUBSCRIPT ZERO..SUBSCRIPT NINE
+208A..208C ; Common # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
+208D ; Common # Ps SUBSCRIPT LEFT PARENTHESIS
+208E ; Common # Pe SUBSCRIPT RIGHT PARENTHESIS
+20A0..20B5 ; Common # Sc [22] EURO-CURRENCY SIGN..CEDI SIGN
+2100..2101 ; Common # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
+2102 ; Common # L& DOUBLE-STRUCK CAPITAL C
+2103..2106 ; Common # So [4] DEGREE CELSIUS..CADA UNA
+2107 ; Common # L& EULER CONSTANT
+2108..2109 ; Common # So [2] SCRUPLE..DEGREE FAHRENHEIT
+210A..2113 ; Common # L& [10] SCRIPT SMALL G..SCRIPT SMALL L
+2114 ; Common # So L B BAR SYMBOL
+2115 ; Common # L& DOUBLE-STRUCK CAPITAL N
+2116..2118 ; Common # So [3] NUMERO SIGN..SCRIPT CAPITAL P
+2119..211D ; Common # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R
+211E..2123 ; Common # So [6] PRESCRIPTION TAKE..VERSICLE
+2124 ; Common # L& DOUBLE-STRUCK CAPITAL Z
+2125 ; Common # So OUNCE SIGN
+2127 ; Common # So INVERTED OHM SIGN
+2128 ; Common # L& BLACK-LETTER CAPITAL Z
+2129 ; Common # So TURNED GREEK SMALL LETTER IOTA
+212C..212D ; Common # L& [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C
+212E ; Common # So ESTIMATED SYMBOL
+212F..2131 ; Common # L& [3] SCRIPT SMALL E..SCRIPT CAPITAL F
+2133..2134 ; Common # L& [2] SCRIPT CAPITAL M..SCRIPT SMALL O
+2135..2138 ; Common # Lo [4] ALEF SYMBOL..DALET SYMBOL
+2139 ; Common # L& INFORMATION SOURCE
+213A..213B ; Common # So [2] ROTATED CAPITAL Q..FACSIMILE SIGN
+213C..213F ; Common # L& [4] DOUBLE-STRUCK SMALL PI..DOUBLE-STRUCK CAPITAL PI
+2140..2144 ; Common # Sm [5] DOUBLE-STRUCK N-ARY SUMMATION..TURNED SANS-SERIF CAPITAL Y
+2145..2149 ; Common # L& [5] DOUBLE-STRUCK ITALIC CAPITAL D..DOUBLE-STRUCK ITALIC SMALL J
+214A ; Common # So PROPERTY LINE
+214B ; Common # Sm TURNED AMPERSAND
+214C..214D ; Common # So [2] PER SIGN..AKTIESELSKAB
+214F ; Common # So SYMBOL FOR SAMARITAN SOURCE
+2153..215F ; Common # No [13] VULGAR FRACTION ONE THIRD..FRACTION NUMERATOR ONE
+2190..2194 ; Common # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW
+2195..2199 ; Common # So [5] UP DOWN ARROW..SOUTH WEST ARROW
+219A..219B ; Common # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE
+219C..219F ; Common # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW
+21A0 ; Common # Sm RIGHTWARDS TWO HEADED ARROW
+21A1..21A2 ; Common # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL
+21A3 ; Common # Sm RIGHTWARDS ARROW WITH TAIL
+21A4..21A5 ; Common # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR
+21A6 ; Common # Sm RIGHTWARDS ARROW FROM BAR
+21A7..21AD ; Common # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW
+21AE ; Common # Sm LEFT RIGHT ARROW WITH STROKE
+21AF..21CD ; Common # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE
+21CE..21CF ; Common # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE
+21D0..21D1 ; Common # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW
+21D2 ; Common # Sm RIGHTWARDS DOUBLE ARROW
+21D3 ; Common # So DOWNWARDS DOUBLE ARROW
+21D4 ; Common # Sm LEFT RIGHT DOUBLE ARROW
+21D5..21F3 ; Common # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
+21F4..22FF ; Common # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
+2300..2307 ; Common # So [8] DIAMETER SIGN..WAVY LINE
+2308..230B ; Common # Sm [4] LEFT CEILING..RIGHT FLOOR
+230C..231F ; Common # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
+2320..2321 ; Common # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
+2322..2328 ; Common # So [7] FROWN..KEYBOARD
+2329 ; Common # Ps LEFT-POINTING ANGLE BRACKET
+232A ; Common # Pe RIGHT-POINTING ANGLE BRACKET
+232B..237B ; Common # So [81] ERASE TO THE LEFT..NOT CHECK MARK
+237C ; Common # Sm RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+237D..239A ; Common # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL
+239B..23B3 ; Common # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
+23B4..23DB ; Common # So [40] TOP SQUARE BRACKET..FUSE
+23DC..23E1 ; Common # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
+23E2..23E7 ; Common # So [6] WHITE TRAPEZIUM..ELECTRICAL INTERSECTION
+2400..2426 ; Common # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
+2440..244A ; Common # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
+2460..249B ; Common # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
+249C..24E9 ; Common # So [78] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
+24EA..24FF ; Common # No [22] CIRCLED DIGIT ZERO..NEGATIVE CIRCLED DIGIT ZERO
+2500..25B6 ; Common # So [183] BOX DRAWINGS LIGHT HORIZONTAL..BLACK RIGHT-POINTING TRIANGLE
+25B7 ; Common # Sm WHITE RIGHT-POINTING TRIANGLE
+25B8..25C0 ; Common # So [9] BLACK RIGHT-POINTING SMALL TRIANGLE..BLACK LEFT-POINTING TRIANGLE
+25C1 ; Common # Sm WHITE LEFT-POINTING TRIANGLE
+25C2..25F7 ; Common # So [54] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE CIRCLE WITH UPPER RIGHT QUADRANT
+25F8..25FF ; Common # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
+2600..266E ; Common # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
+266F ; Common # Sm MUSIC SHARP SIGN
+2670..269D ; Common # So [46] WEST SYRIAC CROSS..OUTLINED WHITE STAR
+26A0..26BC ; Common # So [29] WARNING SIGN..SESQUIQUADRATE
+26C0..26C3 ; Common # So [4] WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+2701..2704 ; Common # So [4] UPPER BLADE SCISSORS..WHITE SCISSORS
+2706..2709 ; Common # So [4] TELEPHONE LOCATION SIGN..ENVELOPE
+270C..2727 ; Common # So [28] VICTORY HAND..WHITE FOUR POINTED STAR
+2729..274B ; Common # So [35] STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK
+274D ; Common # So SHADOWED WHITE CIRCLE
+274F..2752 ; Common # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE
+2756 ; Common # So BLACK DIAMOND MINUS WHITE X
+2758..275E ; Common # So [7] LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT
+2761..2767 ; Common # So [7] CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET
+2768 ; Common # Ps MEDIUM LEFT PARENTHESIS ORNAMENT
+2769 ; Common # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
+276A ; Common # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
+276B ; Common # Pe MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT
+276C ; Common # Ps MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT
+276D ; Common # Pe MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT
+276E ; Common # Ps HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT
+276F ; Common # Pe HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT
+2770 ; Common # Ps HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT
+2771 ; Common # Pe HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT
+2772 ; Common # Ps LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+2773 ; Common # Pe LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+2774 ; Common # Ps MEDIUM LEFT CURLY BRACKET ORNAMENT
+2775 ; Common # Pe MEDIUM RIGHT CURLY BRACKET ORNAMENT
+2776..2793 ; Common # No [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN
+2794 ; Common # So HEAVY WIDE-HEADED RIGHTWARDS ARROW
+2798..27AF ; Common # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW
+27B1..27BE ; Common # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW
+27C0..27C4 ; Common # Sm [5] THREE DIMENSIONAL ANGLE..OPEN SUPERSET
+27C5 ; Common # Ps LEFT S-SHAPED BAG DELIMITER
+27C6 ; Common # Pe RIGHT S-SHAPED BAG DELIMITER
+27C7..27CA ; Common # Sm [4] OR WITH DOT INSIDE..VERTICAL BAR WITH HORIZONTAL STROKE
+27CC ; Common # Sm LONG DIVISION
+27D0..27E5 ; Common # Sm [22] WHITE DIAMOND WITH CENTRED DOT..WHITE SQUARE WITH RIGHTWARDS TICK
+27E6 ; Common # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
+27E7 ; Common # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+27E8 ; Common # Ps MATHEMATICAL LEFT ANGLE BRACKET
+27E9 ; Common # Pe MATHEMATICAL RIGHT ANGLE BRACKET
+27EA ; Common # Ps MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+27EB ; Common # Pe MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+27EC ; Common # Ps MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+27ED ; Common # Pe MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+27EE ; Common # Ps MATHEMATICAL LEFT FLATTENED PARENTHESIS
+27EF ; Common # Pe MATHEMATICAL RIGHT FLATTENED PARENTHESIS
+27F0..27FF ; Common # Sm [16] UPWARDS QUADRUPLE ARROW..LONG RIGHTWARDS SQUIGGLE ARROW
+2900..2982 ; Common # Sm [131] RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE..Z NOTATION TYPE COLON
+2983 ; Common # Ps LEFT WHITE CURLY BRACKET
+2984 ; Common # Pe RIGHT WHITE CURLY BRACKET
+2985 ; Common # Ps LEFT WHITE PARENTHESIS
+2986 ; Common # Pe RIGHT WHITE PARENTHESIS
+2987 ; Common # Ps Z NOTATION LEFT IMAGE BRACKET
+2988 ; Common # Pe Z NOTATION RIGHT IMAGE BRACKET
+2989 ; Common # Ps Z NOTATION LEFT BINDING BRACKET
+298A ; Common # Pe Z NOTATION RIGHT BINDING BRACKET
+298B ; Common # Ps LEFT SQUARE BRACKET WITH UNDERBAR
+298C ; Common # Pe RIGHT SQUARE BRACKET WITH UNDERBAR
+298D ; Common # Ps LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+298E ; Common # Pe RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+298F ; Common # Ps LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+2990 ; Common # Pe RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+2991 ; Common # Ps LEFT ANGLE BRACKET WITH DOT
+2992 ; Common # Pe RIGHT ANGLE BRACKET WITH DOT
+2993 ; Common # Ps LEFT ARC LESS-THAN BRACKET
+2994 ; Common # Pe RIGHT ARC GREATER-THAN BRACKET
+2995 ; Common # Ps DOUBLE LEFT ARC GREATER-THAN BRACKET
+2996 ; Common # Pe DOUBLE RIGHT ARC LESS-THAN BRACKET
+2997 ; Common # Ps LEFT BLACK TORTOISE SHELL BRACKET
+2998 ; Common # Pe RIGHT BLACK TORTOISE SHELL BRACKET
+2999..29D7 ; Common # Sm [63] DOTTED FENCE..BLACK HOURGLASS
+29D8 ; Common # Ps LEFT WIGGLY FENCE
+29D9 ; Common # Pe RIGHT WIGGLY FENCE
+29DA ; Common # Ps LEFT DOUBLE WIGGLY FENCE
+29DB ; Common # Pe RIGHT DOUBLE WIGGLY FENCE
+29DC..29FB ; Common # Sm [32] INCOMPLETE INFINITY..TRIPLE PLUS
+29FC ; Common # Ps LEFT-POINTING CURVED ANGLE BRACKET
+29FD ; Common # Pe RIGHT-POINTING CURVED ANGLE BRACKET
+29FE..2AFF ; Common # Sm [258] TINY..N-ARY WHITE VERTICAL BAR
+2B00..2B2F ; Common # So [48] NORTH EAST WHITE ARROW..WHITE VERTICAL ELLIPSE
+2B30..2B44 ; Common # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
+2B45..2B46 ; Common # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
+2B47..2B4C ; Common # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
+2B50..2B54 ; Common # So [5] WHITE MEDIUM STAR..WHITE RIGHT-POINTING PENTAGON
+2E00..2E01 ; Common # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
+2E02 ; Common # Pi LEFT SUBSTITUTION BRACKET
+2E03 ; Common # Pf RIGHT SUBSTITUTION BRACKET
+2E04 ; Common # Pi LEFT DOTTED SUBSTITUTION BRACKET
+2E05 ; Common # Pf RIGHT DOTTED SUBSTITUTION BRACKET
+2E06..2E08 ; Common # Po [3] RAISED INTERPOLATION MARKER..DOTTED TRANSPOSITION MARKER
+2E09 ; Common # Pi LEFT TRANSPOSITION BRACKET
+2E0A ; Common # Pf RIGHT TRANSPOSITION BRACKET
+2E0B ; Common # Po RAISED SQUARE
+2E0C ; Common # Pi LEFT RAISED OMISSION BRACKET
+2E0D ; Common # Pf RIGHT RAISED OMISSION BRACKET
+2E0E..2E16 ; Common # Po [9] EDITORIAL CORONIS..DOTTED RIGHT-POINTING ANGLE
+2E17 ; Common # Pd DOUBLE OBLIQUE HYPHEN
+2E18..2E19 ; Common # Po [2] INVERTED INTERROBANG..PALM BRANCH
+2E1A ; Common # Pd HYPHEN WITH DIAERESIS
+2E1B ; Common # Po TILDE WITH RING ABOVE
+2E1C ; Common # Pi LEFT LOW PARAPHRASE BRACKET
+2E1D ; Common # Pf RIGHT LOW PARAPHRASE BRACKET
+2E1E..2E1F ; Common # Po [2] TILDE WITH DOT ABOVE..TILDE WITH DOT BELOW
+2E20 ; Common # Pi LEFT VERTICAL BAR WITH QUILL
+2E21 ; Common # Pf RIGHT VERTICAL BAR WITH QUILL
+2E22 ; Common # Ps TOP LEFT HALF BRACKET
+2E23 ; Common # Pe TOP RIGHT HALF BRACKET
+2E24 ; Common # Ps BOTTOM LEFT HALF BRACKET
+2E25 ; Common # Pe BOTTOM RIGHT HALF BRACKET
+2E26 ; Common # Ps LEFT SIDEWAYS U BRACKET
+2E27 ; Common # Pe RIGHT SIDEWAYS U BRACKET
+2E28 ; Common # Ps LEFT DOUBLE PARENTHESIS
+2E29 ; Common # Pe RIGHT DOUBLE PARENTHESIS
+2E2A..2E2E ; Common # Po [5] TWO DOTS OVER ONE DOT PUNCTUATION..REVERSED QUESTION MARK
+2E2F ; Common # Lm VERTICAL TILDE
+2E30 ; Common # Po RING POINT
+2FF0..2FFB ; Common # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
+3000 ; Common # Zs IDEOGRAPHIC SPACE
+3001..3003 ; Common # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
+3004 ; Common # So JAPANESE INDUSTRIAL STANDARD SYMBOL
+3006 ; Common # Lo IDEOGRAPHIC CLOSING MARK
+3008 ; Common # Ps LEFT ANGLE BRACKET
+3009 ; Common # Pe RIGHT ANGLE BRACKET
+300A ; Common # Ps LEFT DOUBLE ANGLE BRACKET
+300B ; Common # Pe RIGHT DOUBLE ANGLE BRACKET
+300C ; Common # Ps LEFT CORNER BRACKET
+300D ; Common # Pe RIGHT CORNER BRACKET
+300E ; Common # Ps LEFT WHITE CORNER BRACKET
+300F ; Common # Pe RIGHT WHITE CORNER BRACKET
+3010 ; Common # Ps LEFT BLACK LENTICULAR BRACKET
+3011 ; Common # Pe RIGHT BLACK LENTICULAR BRACKET
+3012..3013 ; Common # So [2] POSTAL MARK..GETA MARK
+3014 ; Common # Ps LEFT TORTOISE SHELL BRACKET
+3015 ; Common # Pe RIGHT TORTOISE SHELL BRACKET
+3016 ; Common # Ps LEFT WHITE LENTICULAR BRACKET
+3017 ; Common # Pe RIGHT WHITE LENTICULAR BRACKET
+3018 ; Common # Ps LEFT WHITE TORTOISE SHELL BRACKET
+3019 ; Common # Pe RIGHT WHITE TORTOISE SHELL BRACKET
+301A ; Common # Ps LEFT WHITE SQUARE BRACKET
+301B ; Common # Pe RIGHT WHITE SQUARE BRACKET
+301C ; Common # Pd WAVE DASH
+301D ; Common # Ps REVERSED DOUBLE PRIME QUOTATION MARK
+301E..301F ; Common # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
+3020 ; Common # So POSTAL MARK FACE
+3030 ; Common # Pd WAVY DASH
+3031..3035 ; Common # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF
+3036..3037 ; Common # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
+303C ; Common # Lo MASU MARK
+303D ; Common # Po PART ALTERNATION MARK
+303E..303F ; Common # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE
+309B..309C ; Common # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+30A0 ; Common # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
+30FB ; Common # Po KATAKANA MIDDLE DOT
+30FC ; Common # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK
+3190..3191 ; Common # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK
+3192..3195 ; Common # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK
+3196..319F ; Common # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK
+31C0..31E3 ; Common # So [36] CJK STROKE T..CJK STROKE Q
+3220..3229 ; Common # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN
+322A..3243 ; Common # So [26] PARENTHESIZED IDEOGRAPH MOON..PARENTHESIZED IDEOGRAPH REACH
+3250 ; Common # So PARTNERSHIP SIGN
+3251..325F ; Common # No [15] CIRCLED NUMBER TWENTY ONE..CIRCLED NUMBER THIRTY FIVE
+327F ; Common # So KOREAN STANDARD SYMBOL
+3280..3289 ; Common # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN
+328A..32B0 ; Common # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT
+32B1..32BF ; Common # No [15] CIRCLED NUMBER THIRTY SIX..CIRCLED NUMBER FIFTY
+32C0..32CF ; Common # So [16] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..LIMITED LIABILITY SIGN
+3358..33FF ; Common # So [168] IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO..SQUARE GAL
+4DC0..4DFF ; Common # So [64] HEXAGRAM FOR THE CREATIVE HEAVEN..HEXAGRAM FOR BEFORE COMPLETION
+A700..A716 ; Common # Sk [23] MODIFIER LETTER CHINESE TONE YIN PING..MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR
+A717..A71F ; Common # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
+A720..A721 ; Common # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
+A788 ; Common # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
+A789..A78A ; Common # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
+FD3E ; Common # Ps ORNATE LEFT PARENTHESIS
+FD3F ; Common # Pe ORNATE RIGHT PARENTHESIS
+FDFD ; Common # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
+FE10..FE16 ; Common # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
+FE17 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
+FE18 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
+FE19 ; Common # Po PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS
+FE30 ; Common # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER
+FE31..FE32 ; Common # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH
+FE33..FE34 ; Common # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
+FE35 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
+FE36 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
+FE37 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
+FE38 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
+FE39 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
+FE3A ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
+FE3B ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
+FE3C ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
+FE3D ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
+FE3E ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
+FE3F ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
+FE40 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
+FE41 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
+FE42 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
+FE43 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
+FE44 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
+FE45..FE46 ; Common # Po [2] SESAME DOT..WHITE SESAME DOT
+FE47 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET
+FE48 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET
+FE49..FE4C ; Common # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE
+FE4D..FE4F ; Common # Pc [3] DASHED LOW LINE..WAVY LOW LINE
+FE50..FE52 ; Common # Po [3] SMALL COMMA..SMALL FULL STOP
+FE54..FE57 ; Common # Po [4] SMALL SEMICOLON..SMALL EXCLAMATION MARK
+FE58 ; Common # Pd SMALL EM DASH
+FE59 ; Common # Ps SMALL LEFT PARENTHESIS
+FE5A ; Common # Pe SMALL RIGHT PARENTHESIS
+FE5B ; Common # Ps SMALL LEFT CURLY BRACKET
+FE5C ; Common # Pe SMALL RIGHT CURLY BRACKET
+FE5D ; Common # Ps SMALL LEFT TORTOISE SHELL BRACKET
+FE5E ; Common # Pe SMALL RIGHT TORTOISE SHELL BRACKET
+FE5F..FE61 ; Common # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK
+FE62 ; Common # Sm SMALL PLUS SIGN
+FE63 ; Common # Pd SMALL HYPHEN-MINUS
+FE64..FE66 ; Common # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN
+FE68 ; Common # Po SMALL REVERSE SOLIDUS
+FE69 ; Common # Sc SMALL DOLLAR SIGN
+FE6A..FE6B ; Common # Po [2] SMALL PERCENT SIGN..SMALL COMMERCIAL AT
+FEFF ; Common # Cf ZERO WIDTH NO-BREAK SPACE
+FF01..FF03 ; Common # Po [3] FULLWIDTH EXCLAMATION MARK..FULLWIDTH NUMBER SIGN
+FF04 ; Common # Sc FULLWIDTH DOLLAR SIGN
+FF05..FF07 ; Common # Po [3] FULLWIDTH PERCENT SIGN..FULLWIDTH APOSTROPHE
+FF08 ; Common # Ps FULLWIDTH LEFT PARENTHESIS
+FF09 ; Common # Pe FULLWIDTH RIGHT PARENTHESIS
+FF0A ; Common # Po FULLWIDTH ASTERISK
+FF0B ; Common # Sm FULLWIDTH PLUS SIGN
+FF0C ; Common # Po FULLWIDTH COMMA
+FF0D ; Common # Pd FULLWIDTH HYPHEN-MINUS
+FF0E..FF0F ; Common # Po [2] FULLWIDTH FULL STOP..FULLWIDTH SOLIDUS
+FF10..FF19 ; Common # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
+FF1A..FF1B ; Common # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON
+FF1C..FF1E ; Common # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN
+FF1F..FF20 ; Common # Po [2] FULLWIDTH QUESTION MARK..FULLWIDTH COMMERCIAL AT
+FF3B ; Common # Ps FULLWIDTH LEFT SQUARE BRACKET
+FF3C ; Common # Po FULLWIDTH REVERSE SOLIDUS
+FF3D ; Common # Pe FULLWIDTH RIGHT SQUARE BRACKET
+FF3E ; Common # Sk FULLWIDTH CIRCUMFLEX ACCENT
+FF3F ; Common # Pc FULLWIDTH LOW LINE
+FF40 ; Common # Sk FULLWIDTH GRAVE ACCENT
+FF5B ; Common # Ps FULLWIDTH LEFT CURLY BRACKET
+FF5C ; Common # Sm FULLWIDTH VERTICAL LINE
+FF5D ; Common # Pe FULLWIDTH RIGHT CURLY BRACKET
+FF5E ; Common # Sm FULLWIDTH TILDE
+FF5F ; Common # Ps FULLWIDTH LEFT WHITE PARENTHESIS
+FF60 ; Common # Pe FULLWIDTH RIGHT WHITE PARENTHESIS
+FF61 ; Common # Po HALFWIDTH IDEOGRAPHIC FULL STOP
+FF62 ; Common # Ps HALFWIDTH LEFT CORNER BRACKET
+FF63 ; Common # Pe HALFWIDTH RIGHT CORNER BRACKET
+FF64..FF65 ; Common # Po [2] HALFWIDTH IDEOGRAPHIC COMMA..HALFWIDTH KATAKANA MIDDLE DOT
+FF70 ; Common # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
+FF9E..FF9F ; Common # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
+FFE0..FFE1 ; Common # Sc [2] FULLWIDTH CENT SIGN..FULLWIDTH POUND SIGN
+FFE2 ; Common # Sm FULLWIDTH NOT SIGN
+FFE3 ; Common # Sk FULLWIDTH MACRON
+FFE4 ; Common # So FULLWIDTH BROKEN BAR
+FFE5..FFE6 ; Common # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN
+FFE8 ; Common # So HALFWIDTH FORMS LIGHT VERTICAL
+FFE9..FFEC ; Common # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW
+FFED..FFEE ; Common # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE
+FFF9..FFFB ; Common # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR
+FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHARACTER
+10100..10101 ; Common # Po [2] AEGEAN WORD SEPARATOR LINE..AEGEAN WORD SEPARATOR DOT
+10102 ; Common # So AEGEAN CHECK MARK
+10107..10133 ; Common # No [45] AEGEAN NUMBER ONE..AEGEAN NUMBER NINETY THOUSAND
+10137..1013F ; Common # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
+10190..1019B ; Common # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
+101D0..101FC ; Common # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
+1D000..1D0F5 ; Common # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
+1D100..1D126 ; Common # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
+1D129..1D164 ; Common # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
+1D165..1D166 ; Common # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
+1D16A..1D16C ; Common # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3
+1D16D..1D172 ; Common # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5
+1D173..1D17A ; Common # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+1D183..1D184 ; Common # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN
+1D18C..1D1A9 ; Common # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH
+1D1AE..1D1DD ; Common # So [48] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL PES SUBPUNCTIS
+1D300..1D356 ; Common # So [87] MONOGRAM FOR EARTH..TETRAGRAM FOR FOSTERING
+1D360..1D371 ; Common # No [18] COUNTING ROD UNIT DIGIT ONE..COUNTING ROD TENS DIGIT NINE
+1D400..1D454 ; Common # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G
+1D456..1D49C ; Common # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A
+1D49E..1D49F ; Common # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D
+1D4A2 ; Common # L& MATHEMATICAL SCRIPT CAPITAL G
+1D4A5..1D4A6 ; Common # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K
+1D4A9..1D4AC ; Common # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q
+1D4AE..1D4B9 ; Common # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D
+1D4BB ; Common # L& MATHEMATICAL SCRIPT SMALL F
+1D4BD..1D4C3 ; Common # L& [7] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL N
+1D4C5..1D505 ; Common # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B
+1D507..1D50A ; Common # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G
+1D50D..1D514 ; Common # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q
+1D516..1D51C ; Common # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y
+1D51E..1D539 ; Common # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+1D53B..1D53E ; Common # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+1D540..1D544 ; Common # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+1D546 ; Common # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+1D54A..1D550 ; Common # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+1D552..1D6A5 ; Common # L& [340] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL ITALIC SMALL DOTLESS J
+1D6A8..1D6C0 ; Common # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA
+1D6C1 ; Common # Sm MATHEMATICAL BOLD NABLA
+1D6C2..1D6DA ; Common # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA
+1D6DB ; Common # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL
+1D6DC..1D6FA ; Common # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA
+1D6FB ; Common # Sm MATHEMATICAL ITALIC NABLA
+1D6FC..1D714 ; Common # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA
+1D715 ; Common # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL
+1D716..1D734 ; Common # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA
+1D735 ; Common # Sm MATHEMATICAL BOLD ITALIC NABLA
+1D736..1D74E ; Common # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA
+1D74F ; Common # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL
+1D750..1D76E ; Common # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA
+1D76F ; Common # Sm MATHEMATICAL SANS-SERIF BOLD NABLA
+1D770..1D788 ; Common # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA
+1D789 ; Common # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL
+1D78A..1D7A8 ; Common # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA
+1D7A9 ; Common # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA
+1D7AA..1D7C2 ; Common # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA
+1D7C3 ; Common # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL
+1D7C4..1D7CB ; Common # L& [8] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD SMALL DIGAMMA
+1D7CE..1D7FF ; Common # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE
+1F000..1F02B ; Common # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F030..1F093 ; Common # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+E0001 ; Common # Cf LANGUAGE TAG
+E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG
+
+# Total code points: 5178
+
+# ================================================
+
+0041..005A ; Latin # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z
+0061..007A ; Latin # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
+00AA ; Latin # L& FEMININE ORDINAL INDICATOR
+00BA ; Latin # L& MASCULINE ORDINAL INDICATOR
+00C0..00D6 ; Latin # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8..00F6 ; Latin # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
+00F8..01BA ; Latin # L& [195] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER EZH WITH TAIL
+01BB ; Latin # Lo LATIN LETTER TWO WITH STROKE
+01BC..01BF ; Latin # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
+01C0..01C3 ; Latin # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
+01C4..0293 ; Latin # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
+0294 ; Latin # Lo LATIN LETTER GLOTTAL STOP
+0295..02AF ; Latin # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+02B0..02B8 ; Latin # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y
+02E0..02E4 ; Latin # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP
+1D00..1D25 ; Latin # L& [38] LATIN LETTER SMALL CAPITAL A..LATIN LETTER AIN
+1D2C..1D5C ; Latin # Lm [49] MODIFIER LETTER CAPITAL A..MODIFIER LETTER SMALL AIN
+1D62..1D65 ; Latin # L& [4] LATIN SUBSCRIPT SMALL LETTER I..LATIN SUBSCRIPT SMALL LETTER V
+1D6B..1D77 ; Latin # L& [13] LATIN SMALL LETTER UE..LATIN SMALL LETTER TURNED G
+1D79..1D9A ; Latin # L& [34] LATIN SMALL LETTER INSULAR G..LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+1D9B..1DBE ; Latin # Lm [36] MODIFIER LETTER SMALL TURNED ALPHA..MODIFIER LETTER SMALL EZH
+1E00..1EFF ; Latin # L& [256] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER Y WITH LOOP
+2071 ; Latin # L& SUPERSCRIPT LATIN SMALL LETTER I
+207F ; Latin # L& SUPERSCRIPT LATIN SMALL LETTER N
+2090..2094 ; Latin # Lm [5] LATIN SUBSCRIPT SMALL LETTER A..LATIN SUBSCRIPT SMALL LETTER SCHWA
+212A..212B ; Latin # L& [2] KELVIN SIGN..ANGSTROM SIGN
+2132 ; Latin # L& TURNED CAPITAL F
+214E ; Latin # L& TURNED SMALL F
+2160..2182 ; Latin # Nl [35] ROMAN NUMERAL ONE..ROMAN NUMERAL TEN THOUSAND
+2183..2184 ; Latin # L& [2] ROMAN NUMERAL REVERSED ONE HUNDRED..LATIN SMALL LETTER REVERSED C
+2185..2188 ; Latin # Nl [4] ROMAN NUMERAL SIX LATE FORM..ROMAN NUMERAL ONE HUNDRED THOUSAND
+2C60..2C6F ; Latin # L& [16] LATIN CAPITAL LETTER L WITH DOUBLE BAR..LATIN CAPITAL LETTER TURNED A
+2C71..2C7C ; Latin # L& [12] LATIN SMALL LETTER V WITH RIGHT HOOK..LATIN SUBSCRIPT SMALL LETTER J
+2C7D ; Latin # Lm MODIFIER LETTER CAPITAL V
+A722..A76F ; Latin # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN SMALL LETTER CON
+A770 ; Latin # Lm MODIFIER LETTER US
+A771..A787 ; Latin # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
+A78B..A78C ; Latin # L& [2] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER SALTILLO
+A7FB..A7FF ; Latin # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M
+FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
+FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
+FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
+
+# Total code points: 1241
+
+# ================================================
+
+0370..0373 ; Greek # L& [4] GREEK CAPITAL LETTER HETA..GREEK SMALL LETTER ARCHAIC SAMPI
+0375 ; Greek # Sk GREEK LOWER NUMERAL SIGN
+0376..0377 ; Greek # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
+037A ; Greek # Lm GREEK YPOGEGRAMMENI
+037B..037D ; Greek # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0384 ; Greek # Sk GREEK TONOS
+0386 ; Greek # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388..038A ; Greek # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
+038C ; Greek # L& GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E..03A1 ; Greek # L& [20] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK CAPITAL LETTER RHO
+03A3..03E1 ; Greek # L& [63] GREEK CAPITAL LETTER SIGMA..GREEK SMALL LETTER SAMPI
+03F0..03F5 ; Greek # L& [6] GREEK KAPPA SYMBOL..GREEK LUNATE EPSILON SYMBOL
+03F6 ; Greek # Sm GREEK REVERSED LUNATE EPSILON SYMBOL
+03F7..03FF ; Greek # L& [9] GREEK CAPITAL LETTER SHO..GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+1D26..1D2A ; Greek # L& [5] GREEK LETTER SMALL CAPITAL GAMMA..GREEK LETTER SMALL CAPITAL PSI
+1D5D..1D61 ; Greek # Lm [5] MODIFIER LETTER SMALL BETA..MODIFIER LETTER SMALL CHI
+1D66..1D6A ; Greek # L& [5] GREEK SUBSCRIPT SMALL LETTER BETA..GREEK SUBSCRIPT SMALL LETTER CHI
+1DBF ; Greek # Lm MODIFIER LETTER SMALL THETA
+1F00..1F15 ; Greek # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+1F18..1F1D ; Greek # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F20..1F45 ; Greek # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+1F48..1F4D ; Greek # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50..1F57 ; Greek # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F59 ; Greek # L& GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B ; Greek # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D ; Greek # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F..1F7D ; Greek # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA
+1F80..1FB4 ; Greek # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6..1FBC ; Greek # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBD ; Greek # Sk GREEK KORONIS
+1FBE ; Greek # L& GREEK PROSGEGRAMMENI
+1FBF..1FC1 ; Greek # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
+1FC2..1FC4 ; Greek # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6..1FCC ; Greek # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCD..1FCF ; Greek # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI
+1FD0..1FD3 ; Greek # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6..1FDB ; Greek # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA
+1FDD..1FDF ; Greek # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI
+1FE0..1FEC ; Greek # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA
+1FED..1FEF ; Greek # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA
+1FF2..1FF4 ; Greek # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6..1FFC ; Greek # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFD..1FFE ; Greek # Sk [2] GREEK OXIA..GREEK DASIA
+2126 ; Greek # L& OHM SIGN
+10140..10174 ; Greek # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
+10175..10178 ; Greek # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
+10179..10189 ; Greek # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
+1018A ; Greek # No GREEK ZERO SIGN
+1D200..1D241 ; Greek # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
+1D242..1D244 ; Greek # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
+1D245 ; Greek # So GREEK MUSICAL LEIMMA
+
+# Total code points: 511
+
+# ================================================
+
+0400..0481 ; Cyrillic # L& [130] CYRILLIC CAPITAL LETTER IE WITH GRAVE..CYRILLIC SMALL LETTER KOPPA
+0482 ; Cyrillic # So CYRILLIC THOUSANDS SIGN
+0483..0487 ; Cyrillic # Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE
+0488..0489 ; Cyrillic # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
+048A..0523 ; Cyrillic # L& [154] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK
+1D2B ; Cyrillic # L& CYRILLIC LETTER SMALL CAPITAL EL
+1D78 ; Cyrillic # Lm MODIFIER LETTER CYRILLIC EN
+2DE0..2DFF ; Cyrillic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
+A640..A65F ; Cyrillic # L& [32] CYRILLIC CAPITAL LETTER ZEMLYA..CYRILLIC SMALL LETTER YN
+A662..A66D ; Cyrillic # L& [12] CYRILLIC CAPITAL LETTER SOFT DE..CYRILLIC SMALL LETTER DOUBLE MONOCULAR O
+A66E ; Cyrillic # Lo CYRILLIC LETTER MULTIOCULAR O
+A66F ; Cyrillic # Mn COMBINING CYRILLIC VZMET
+A670..A672 ; Cyrillic # Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN
+A673 ; Cyrillic # Po SLAVONIC ASTERISK
+A67C..A67D ; Cyrillic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
+A67E ; Cyrillic # Po CYRILLIC KAVYKA
+A67F ; Cyrillic # Lm CYRILLIC PAYEROK
+A680..A697 ; Cyrillic # L& [24] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER SHWE
+
+# Total code points: 404
+
+# ================================================
+
+0531..0556 ; Armenian # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH
+0559 ; Armenian # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING
+055A..055F ; Armenian # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
+0561..0587 ; Armenian # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
+058A ; Armenian # Pd ARMENIAN HYPHEN
+FB13..FB17 ; Armenian # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
+
+# Total code points: 90
+
+# ================================================
+
+0591..05BD ; Hebrew # Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG
+05BE ; Hebrew # Pd HEBREW PUNCTUATION MAQAF
+05BF ; Hebrew # Mn HEBREW POINT RAFE
+05C0 ; Hebrew # Po HEBREW PUNCTUATION PASEQ
+05C1..05C2 ; Hebrew # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT
+05C3 ; Hebrew # Po HEBREW PUNCTUATION SOF PASUQ
+05C4..05C5 ; Hebrew # Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT
+05C6 ; Hebrew # Po HEBREW PUNCTUATION NUN HAFUKHA
+05C7 ; Hebrew # Mn HEBREW POINT QAMATS QATAN
+05D0..05EA ; Hebrew # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV
+05F0..05F2 ; Hebrew # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD
+05F3..05F4 ; Hebrew # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM
+FB1D ; Hebrew # Lo HEBREW LETTER YOD WITH HIRIQ
+FB1E ; Hebrew # Mn HEBREW POINT JUDEO-SPANISH VARIKA
+FB1F..FB28 ; Hebrew # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV
+FB29 ; Hebrew # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN
+FB2A..FB36 ; Hebrew # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH
+FB38..FB3C ; Hebrew # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH
+FB3E ; Hebrew # Lo HEBREW LETTER MEM WITH DAGESH
+FB40..FB41 ; Hebrew # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH
+FB43..FB44 ; Hebrew # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH
+FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATURE ALEF LAMED
+
+# Total code points: 133
+
+# ================================================
+
+0606..0608 ; Arabic # Sm [3] ARABIC-INDIC CUBE ROOT..ARABIC RAY
+0609..060A ; Arabic # Po [2] ARABIC-INDIC PER MILLE SIGN..ARABIC-INDIC PER TEN THOUSAND SIGN
+060B ; Arabic # Sc AFGHANI SIGN
+060D ; Arabic # Po ARABIC DATE SEPARATOR
+060E..060F ; Arabic # So [2] ARABIC POETIC VERSE SIGN..ARABIC SIGN MISRA
+0610..061A ; Arabic # Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA
+061E ; Arabic # Po ARABIC TRIPLE DOT PUNCTUATION MARK
+0621..063F ; Arabic # Lo [31] ARABIC LETTER HAMZA..ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
+0641..064A ; Arabic # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH
+0656..065E ; Arabic # Mn [9] ARABIC SUBSCRIPT ALEF..ARABIC FATHA WITH TWO DOTS
+066A..066D ; Arabic # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR
+066E..066F ; Arabic # Lo [2] ARABIC LETTER DOTLESS BEH..ARABIC LETTER DOTLESS QAF
+0671..06D3 ; Arabic # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE
+06D4 ; Arabic # Po ARABIC FULL STOP
+06D5 ; Arabic # Lo ARABIC LETTER AE
+06D6..06DC ; Arabic # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN
+06DE ; Arabic # Me ARABIC START OF RUB EL HIZB
+06DF..06E4 ; Arabic # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA
+06E5..06E6 ; Arabic # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH
+06E7..06E8 ; Arabic # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON
+06E9 ; Arabic # So ARABIC PLACE OF SAJDAH
+06EA..06ED ; Arabic # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM
+06EE..06EF ; Arabic # Lo [2] ARABIC LETTER DAL WITH INVERTED V..ARABIC LETTER REH WITH INVERTED V
+06F0..06F9 ; Arabic # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE
+06FA..06FC ; Arabic # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW
+06FD..06FE ; Arabic # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
+06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V
+0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE
+FB50..FBB1 ; Arabic # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
+FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
+FD50..FD8F ; Arabic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM
+FD92..FDC7 ; Arabic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
+FDF0..FDFB ; Arabic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
+FDFC ; Arabic # Sc RIAL SIGN
+FE70..FE74 ; Arabic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
+FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
+
+# Total code points: 999
+
+# ================================================
+
+0700..070D ; Syriac # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS
+070F ; Syriac # Cf SYRIAC ABBREVIATION MARK
+0710 ; Syriac # Lo SYRIAC LETTER ALAPH
+0711 ; Syriac # Mn SYRIAC LETTER SUPERSCRIPT ALAPH
+0712..072F ; Syriac # Lo [30] SYRIAC LETTER BETH..SYRIAC LETTER PERSIAN DHALATH
+0730..074A ; Syriac # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
+074D..074F ; Syriac # Lo [3] SYRIAC LETTER SOGDIAN ZHAIN..SYRIAC LETTER SOGDIAN FE
+
+# Total code points: 77
+
+# ================================================
+
+0780..07A5 ; Thaana # Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU
+07A6..07B0 ; Thaana # Mn [11] THAANA ABAFILI..THAANA SUKUN
+07B1 ; Thaana # Lo THAANA LETTER NAA
+
+# Total code points: 50
+
+# ================================================
+
+0901..0902 ; Devanagari # Mn [2] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN ANUSVARA
+0903 ; Devanagari # Mc DEVANAGARI SIGN VISARGA
+0904..0939 ; Devanagari # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
+093C ; Devanagari # Mn DEVANAGARI SIGN NUKTA
+093D ; Devanagari # Lo DEVANAGARI SIGN AVAGRAHA
+093E..0940 ; Devanagari # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II
+0941..0948 ; Devanagari # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI
+0949..094C ; Devanagari # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU
+094D ; Devanagari # Mn DEVANAGARI SIGN VIRAMA
+0950 ; Devanagari # Lo DEVANAGARI OM
+0953..0954 ; Devanagari # Mn [2] DEVANAGARI GRAVE ACCENT..DEVANAGARI ACUTE ACCENT
+0958..0961 ; Devanagari # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL
+0962..0963 ; Devanagari # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL
+0966..096F ; Devanagari # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
+0971 ; Devanagari # Lm DEVANAGARI SIGN HIGH SPACING DOT
+0972 ; Devanagari # Lo DEVANAGARI LETTER CANDRA A
+097B..097F ; Devanagari # Lo [5] DEVANAGARI LETTER GGA..DEVANAGARI LETTER BBA
+
+# Total code points: 107
+
+# ================================================
+
+0981 ; Bengali # Mn BENGALI SIGN CANDRABINDU
+0982..0983 ; Bengali # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
+0985..098C ; Bengali # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
+098F..0990 ; Bengali # Lo [2] BENGALI LETTER E..BENGALI LETTER AI
+0993..09A8 ; Bengali # Lo [22] BENGALI LETTER O..BENGALI LETTER NA
+09AA..09B0 ; Bengali # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA
+09B2 ; Bengali # Lo BENGALI LETTER LA
+09B6..09B9 ; Bengali # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA
+09BC ; Bengali # Mn BENGALI SIGN NUKTA
+09BD ; Bengali # Lo BENGALI SIGN AVAGRAHA
+09BE..09C0 ; Bengali # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II
+09C1..09C4 ; Bengali # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR
+09C7..09C8 ; Bengali # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI
+09CB..09CC ; Bengali # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU
+09CD ; Bengali # Mn BENGALI SIGN VIRAMA
+09CE ; Bengali # Lo BENGALI LETTER KHANDA TA
+09D7 ; Bengali # Mc BENGALI AU LENGTH MARK
+09DC..09DD ; Bengali # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA
+09DF..09E1 ; Bengali # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL
+09E2..09E3 ; Bengali # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09E6..09EF ; Bengali # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE
+09F0..09F1 ; Bengali # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL
+09F2..09F3 ; Bengali # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN
+09F4..09F9 ; Bengali # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN
+09FA ; Bengali # So BENGALI ISSHAR
+
+# Total code points: 91
+
+# ================================================
+
+0A01..0A02 ; Gurmukhi # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
+0A03 ; Gurmukhi # Mc GURMUKHI SIGN VISARGA
+0A05..0A0A ; Gurmukhi # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU
+0A0F..0A10 ; Gurmukhi # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI
+0A13..0A28 ; Gurmukhi # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA
+0A2A..0A30 ; Gurmukhi # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA
+0A32..0A33 ; Gurmukhi # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA
+0A35..0A36 ; Gurmukhi # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA
+0A38..0A39 ; Gurmukhi # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA
+0A3C ; Gurmukhi # Mn GURMUKHI SIGN NUKTA
+0A3E..0A40 ; Gurmukhi # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II
+0A41..0A42 ; Gurmukhi # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
+0A47..0A48 ; Gurmukhi # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI
+0A4B..0A4D ; Gurmukhi # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA
+0A51 ; Gurmukhi # Mn GURMUKHI SIGN UDAAT
+0A59..0A5C ; Gurmukhi # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA
+0A5E ; Gurmukhi # Lo GURMUKHI LETTER FA
+0A66..0A6F ; Gurmukhi # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE
+0A70..0A71 ; Gurmukhi # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK
+0A72..0A74 ; Gurmukhi # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR
+0A75 ; Gurmukhi # Mn GURMUKHI SIGN YAKASH
+
+# Total code points: 79
+
+# ================================================
+
+0A81..0A82 ; Gujarati # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA
+0A83 ; Gujarati # Mc GUJARATI SIGN VISARGA
+0A85..0A8D ; Gujarati # Lo [9] GUJARATI LETTER A..GUJARATI VOWEL CANDRA E
+0A8F..0A91 ; Gujarati # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O
+0A93..0AA8 ; Gujarati # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA
+0AAA..0AB0 ; Gujarati # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA
+0AB2..0AB3 ; Gujarati # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA
+0AB5..0AB9 ; Gujarati # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA
+0ABC ; Gujarati # Mn GUJARATI SIGN NUKTA
+0ABD ; Gujarati # Lo GUJARATI SIGN AVAGRAHA
+0ABE..0AC0 ; Gujarati # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II
+0AC1..0AC5 ; Gujarati # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E
+0AC7..0AC8 ; Gujarati # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI
+0AC9 ; Gujarati # Mc GUJARATI VOWEL SIGN CANDRA O
+0ACB..0ACC ; Gujarati # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU
+0ACD ; Gujarati # Mn GUJARATI SIGN VIRAMA
+0AD0 ; Gujarati # Lo GUJARATI OM
+0AE0..0AE1 ; Gujarati # Lo [2] GUJARATI LETTER VOCALIC RR..GUJARATI LETTER VOCALIC LL
+0AE2..0AE3 ; Gujarati # Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL
+0AE6..0AEF ; Gujarati # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE
+0AF1 ; Gujarati # Sc GUJARATI RUPEE SIGN
+
+# Total code points: 83
+
+# ================================================
+
+0B01 ; Oriya # Mn ORIYA SIGN CANDRABINDU
+0B02..0B03 ; Oriya # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA
+0B05..0B0C ; Oriya # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L
+0B0F..0B10 ; Oriya # Lo [2] ORIYA LETTER E..ORIYA LETTER AI
+0B13..0B28 ; Oriya # Lo [22] ORIYA LETTER O..ORIYA LETTER NA
+0B2A..0B30 ; Oriya # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA
+0B32..0B33 ; Oriya # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA
+0B35..0B39 ; Oriya # Lo [5] ORIYA LETTER VA..ORIYA LETTER HA
+0B3C ; Oriya # Mn ORIYA SIGN NUKTA
+0B3D ; Oriya # Lo ORIYA SIGN AVAGRAHA
+0B3E ; Oriya # Mc ORIYA VOWEL SIGN AA
+0B3F ; Oriya # Mn ORIYA VOWEL SIGN I
+0B40 ; Oriya # Mc ORIYA VOWEL SIGN II
+0B41..0B44 ; Oriya # Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR
+0B47..0B48 ; Oriya # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI
+0B4B..0B4C ; Oriya # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU
+0B4D ; Oriya # Mn ORIYA SIGN VIRAMA
+0B56 ; Oriya # Mn ORIYA AI LENGTH MARK
+0B57 ; Oriya # Mc ORIYA AU LENGTH MARK
+0B5C..0B5D ; Oriya # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA
+0B5F..0B61 ; Oriya # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL
+0B62..0B63 ; Oriya # Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL
+0B66..0B6F ; Oriya # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE
+0B70 ; Oriya # So ORIYA ISSHAR
+0B71 ; Oriya # Lo ORIYA LETTER WA
+
+# Total code points: 84
+
+# ================================================
+
+0B82 ; Tamil # Mn TAMIL SIGN ANUSVARA
+0B83 ; Tamil # Lo TAMIL SIGN VISARGA
+0B85..0B8A ; Tamil # Lo [6] TAMIL LETTER A..TAMIL LETTER UU
+0B8E..0B90 ; Tamil # Lo [3] TAMIL LETTER E..TAMIL LETTER AI
+0B92..0B95 ; Tamil # Lo [4] TAMIL LETTER O..TAMIL LETTER KA
+0B99..0B9A ; Tamil # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA
+0B9C ; Tamil # Lo TAMIL LETTER JA
+0B9E..0B9F ; Tamil # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA
+0BA3..0BA4 ; Tamil # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA
+0BA8..0BAA ; Tamil # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA
+0BAE..0BB9 ; Tamil # Lo [12] TAMIL LETTER MA..TAMIL LETTER HA
+0BBE..0BBF ; Tamil # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I
+0BC0 ; Tamil # Mn TAMIL VOWEL SIGN II
+0BC1..0BC2 ; Tamil # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU
+0BC6..0BC8 ; Tamil # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
+0BCA..0BCC ; Tamil # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
+0BCD ; Tamil # Mn TAMIL SIGN VIRAMA
+0BD0 ; Tamil # Lo TAMIL OM
+0BD7 ; Tamil # Mc TAMIL AU LENGTH MARK
+0BE6..0BEF ; Tamil # Nd [10] TAMIL DIGIT ZERO..TAMIL DIGIT NINE
+0BF0..0BF2 ; Tamil # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND
+0BF3..0BF8 ; Tamil # So [6] TAMIL DAY SIGN..TAMIL AS ABOVE SIGN
+0BF9 ; Tamil # Sc TAMIL RUPEE SIGN
+0BFA ; Tamil # So TAMIL NUMBER SIGN
+
+# Total code points: 72
+
+# ================================================
+
+0C01..0C03 ; Telugu # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
+0C05..0C0C ; Telugu # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
+0C0E..0C10 ; Telugu # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
+0C12..0C28 ; Telugu # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
+0C2A..0C33 ; Telugu # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA
+0C35..0C39 ; Telugu # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA
+0C3D ; Telugu # Lo TELUGU SIGN AVAGRAHA
+0C3E..0C40 ; Telugu # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
+0C41..0C44 ; Telugu # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
+0C46..0C48 ; Telugu # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
+0C4A..0C4D ; Telugu # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
+0C55..0C56 ; Telugu # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
+0C58..0C59 ; Telugu # Lo [2] TELUGU LETTER TSA..TELUGU LETTER DZA
+0C60..0C61 ; Telugu # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
+0C62..0C63 ; Telugu # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
+0C66..0C6F ; Telugu # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE
+0C78..0C7E ; Telugu # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
+0C7F ; Telugu # So TELUGU SIGN TUUMU
+
+# Total code points: 93
+
+# ================================================
+
+0C82..0C83 ; Kannada # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
+0C85..0C8C ; Kannada # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
+0C8E..0C90 ; Kannada # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
+0C92..0CA8 ; Kannada # Lo [23] KANNADA LETTER O..KANNADA LETTER NA
+0CAA..0CB3 ; Kannada # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
+0CB5..0CB9 ; Kannada # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
+0CBC ; Kannada # Mn KANNADA SIGN NUKTA
+0CBD ; Kannada # Lo KANNADA SIGN AVAGRAHA
+0CBE ; Kannada # Mc KANNADA VOWEL SIGN AA
+0CBF ; Kannada # Mn KANNADA VOWEL SIGN I
+0CC0..0CC4 ; Kannada # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR
+0CC6 ; Kannada # Mn KANNADA VOWEL SIGN E
+0CC7..0CC8 ; Kannada # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI
+0CCA..0CCB ; Kannada # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO
+0CCC..0CCD ; Kannada # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA
+0CD5..0CD6 ; Kannada # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
+0CDE ; Kannada # Lo KANNADA LETTER FA
+0CE0..0CE1 ; Kannada # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
+0CE2..0CE3 ; Kannada # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
+0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
+
+# Total code points: 84
+
+# ================================================
+
+0D02..0D03 ; Malayalam # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
+0D05..0D0C ; Malayalam # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
+0D0E..0D10 ; Malayalam # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
+0D12..0D28 ; Malayalam # Lo [23] MALAYALAM LETTER O..MALAYALAM LETTER NA
+0D2A..0D39 ; Malayalam # Lo [16] MALAYALAM LETTER PA..MALAYALAM LETTER HA
+0D3D ; Malayalam # Lo MALAYALAM SIGN AVAGRAHA
+0D3E..0D40 ; Malayalam # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
+0D41..0D44 ; Malayalam # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
+0D46..0D48 ; Malayalam # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI
+0D4A..0D4C ; Malayalam # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU
+0D4D ; Malayalam # Mn MALAYALAM SIGN VIRAMA
+0D57 ; Malayalam # Mc MALAYALAM AU LENGTH MARK
+0D60..0D61 ; Malayalam # Lo [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL
+0D62..0D63 ; Malayalam # Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL
+0D66..0D6F ; Malayalam # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE
+0D70..0D75 ; Malayalam # No [6] MALAYALAM NUMBER TEN..MALAYALAM FRACTION THREE QUARTERS
+0D79 ; Malayalam # So MALAYALAM DATE MARK
+0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
+
+# Total code points: 95
+
+# ================================================
+
+0D82..0D83 ; Sinhala # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA
+0D85..0D96 ; Sinhala # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA
+0D9A..0DB1 ; Sinhala # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA
+0DB3..0DBB ; Sinhala # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA
+0DBD ; Sinhala # Lo SINHALA LETTER DANTAJA LAYANNA
+0DC0..0DC6 ; Sinhala # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA
+0DCA ; Sinhala # Mn SINHALA SIGN AL-LAKUNA
+0DCF..0DD1 ; Sinhala # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA
+0DD2..0DD4 ; Sinhala # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
+0DD6 ; Sinhala # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
+0DD8..0DDF ; Sinhala # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
+0DF2..0DF3 ; Sinhala # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
+0DF4 ; Sinhala # Po SINHALA PUNCTUATION KUNDDALIYA
+
+# Total code points: 80
+
+# ================================================
+
+0E01..0E30 ; Thai # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A
+0E31 ; Thai # Mn THAI CHARACTER MAI HAN-AKAT
+0E32..0E33 ; Thai # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
+0E34..0E3A ; Thai # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU
+0E40..0E45 ; Thai # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO
+0E46 ; Thai # Lm THAI CHARACTER MAIYAMOK
+0E47..0E4E ; Thai # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN
+0E4F ; Thai # Po THAI CHARACTER FONGMAN
+0E50..0E59 ; Thai # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE
+0E5A..0E5B ; Thai # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT
+
+# Total code points: 86
+
+# ================================================
+
+0E81..0E82 ; Lao # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG
+0E84 ; Lao # Lo LAO LETTER KHO TAM
+0E87..0E88 ; Lao # Lo [2] LAO LETTER NGO..LAO LETTER CO
+0E8A ; Lao # Lo LAO LETTER SO TAM
+0E8D ; Lao # Lo LAO LETTER NYO
+0E94..0E97 ; Lao # Lo [4] LAO LETTER DO..LAO LETTER THO TAM
+0E99..0E9F ; Lao # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG
+0EA1..0EA3 ; Lao # Lo [3] LAO LETTER MO..LAO LETTER LO LING
+0EA5 ; Lao # Lo LAO LETTER LO LOOT
+0EA7 ; Lao # Lo LAO LETTER WO
+0EAA..0EAB ; Lao # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG
+0EAD..0EB0 ; Lao # Lo [4] LAO LETTER O..LAO VOWEL SIGN A
+0EB1 ; Lao # Mn LAO VOWEL SIGN MAI KAN
+0EB2..0EB3 ; Lao # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM
+0EB4..0EB9 ; Lao # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU
+0EBB..0EBC ; Lao # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO
+0EBD ; Lao # Lo LAO SEMIVOWEL SIGN NYO
+0EC0..0EC4 ; Lao # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI
+0EC6 ; Lao # Lm LAO KO LA
+0EC8..0ECD ; Lao # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA
+0ED0..0ED9 ; Lao # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE
+0EDC..0EDD ; Lao # Lo [2] LAO HO NO..LAO HO MO
+
+# Total code points: 65
+
+# ================================================
+
+0F00 ; Tibetan # Lo TIBETAN SYLLABLE OM
+0F01..0F03 ; Tibetan # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA
+0F04..0F12 ; Tibetan # Po [15] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK RGYA GRAM SHAD
+0F13..0F17 ; Tibetan # So [5] TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS
+0F18..0F19 ; Tibetan # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS
+0F1A..0F1F ; Tibetan # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG
+0F20..0F29 ; Tibetan # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE
+0F2A..0F33 ; Tibetan # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO
+0F34 ; Tibetan # So TIBETAN MARK BSDUS RTAGS
+0F35 ; Tibetan # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
+0F36 ; Tibetan # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN
+0F37 ; Tibetan # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
+0F38 ; Tibetan # So TIBETAN MARK CHE MGO
+0F39 ; Tibetan # Mn TIBETAN MARK TSA -PHRU
+0F3A ; Tibetan # Ps TIBETAN MARK GUG RTAGS GYON
+0F3B ; Tibetan # Pe TIBETAN MARK GUG RTAGS GYAS
+0F3C ; Tibetan # Ps TIBETAN MARK ANG KHANG GYON
+0F3D ; Tibetan # Pe TIBETAN MARK ANG KHANG GYAS
+0F3E..0F3F ; Tibetan # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES
+0F40..0F47 ; Tibetan # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA
+0F49..0F6C ; Tibetan # Lo [36] TIBETAN LETTER NYA..TIBETAN LETTER RRA
+0F71..0F7E ; Tibetan # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO
+0F7F ; Tibetan # Mc TIBETAN SIGN RNAM BCAD
+0F80..0F84 ; Tibetan # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA
+0F85 ; Tibetan # Po TIBETAN MARK PALUTA
+0F86..0F87 ; Tibetan # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS
+0F88..0F8B ; Tibetan # Lo [4] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN GRU MED RGYINGS
+0F90..0F97 ; Tibetan # Mn [8] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA
+0F99..0FBC ; Tibetan # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA
+0FBE..0FC5 ; Tibetan # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE
+0FC6 ; Tibetan # Mn TIBETAN SYMBOL PADMA GDAN
+0FC7..0FCC ; Tibetan # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL
+0FCE..0FCF ; Tibetan # So [2] TIBETAN SIGN RDEL NAG RDEL DKAR..TIBETAN SIGN RDEL NAG GSUM
+0FD0..0FD4 ; Tibetan # Po [5] TIBETAN MARK BSKA- SHOG GI MGO RGYAN..TIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB MA
+
+# Total code points: 201
+
+# ================================================
+
+1000..102A ; Myanmar # Lo [43] MYANMAR LETTER KA..MYANMAR LETTER AU
+102B..102C ; Myanmar # Mc [2] MYANMAR VOWEL SIGN TALL AA..MYANMAR VOWEL SIGN AA
+102D..1030 ; Myanmar # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU
+1031 ; Myanmar # Mc MYANMAR VOWEL SIGN E
+1032..1037 ; Myanmar # Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW
+1038 ; Myanmar # Mc MYANMAR SIGN VISARGA
+1039..103A ; Myanmar # Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT
+103B..103C ; Myanmar # Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA
+103D..103E ; Myanmar # Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA
+103F ; Myanmar # Lo MYANMAR LETTER GREAT SA
+1040..1049 ; Myanmar # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE
+104A..104F ; Myanmar # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE
+1050..1055 ; Myanmar # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL
+1056..1057 ; Myanmar # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR
+1058..1059 ; Myanmar # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL
+105A..105D ; Myanmar # Lo [4] MYANMAR LETTER MON NGA..MYANMAR LETTER MON BBE
+105E..1060 ; Myanmar # Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA
+1061 ; Myanmar # Lo MYANMAR LETTER SGAW KAREN SHA
+1062..1064 ; Myanmar # Mc [3] MYANMAR VOWEL SIGN SGAW KAREN EU..MYANMAR TONE MARK SGAW KAREN KE PHO
+1065..1066 ; Myanmar # Lo [2] MYANMAR LETTER WESTERN PWO KAREN THA..MYANMAR LETTER WESTERN PWO KAREN PWA
+1067..106D ; Myanmar # Mc [7] MYANMAR VOWEL SIGN WESTERN PWO KAREN EU..MYANMAR SIGN WESTERN PWO KAREN TONE-5
+106E..1070 ; Myanmar # Lo [3] MYANMAR LETTER EASTERN PWO KAREN NNA..MYANMAR LETTER EASTERN PWO KAREN GHWA
+1071..1074 ; Myanmar # Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE
+1075..1081 ; Myanmar # Lo [13] MYANMAR LETTER SHAN KA..MYANMAR LETTER SHAN HA
+1082 ; Myanmar # Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+1083..1084 ; Myanmar # Mc [2] MYANMAR VOWEL SIGN SHAN AA..MYANMAR VOWEL SIGN SHAN E
+1085..1086 ; Myanmar # Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y
+1087..108C ; Myanmar # Mc [6] MYANMAR SIGN SHAN TONE-2..MYANMAR SIGN SHAN COUNCIL TONE-3
+108D ; Myanmar # Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE
+108E ; Myanmar # Lo MYANMAR LETTER RUMAI PALAUNG FA
+108F ; Myanmar # Mc MYANMAR SIGN RUMAI PALAUNG TONE-5
+1090..1099 ; Myanmar # Nd [10] MYANMAR SHAN DIGIT ZERO..MYANMAR SHAN DIGIT NINE
+109E..109F ; Myanmar # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
+
+# Total code points: 156
+
+# ================================================
+
+10A0..10C5 ; Georgian # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE
+10D0..10FA ; Georgian # Lo [43] GEORGIAN LETTER AN..GEORGIAN LETTER AIN
+10FC ; Georgian # Lm MODIFIER LETTER GEORGIAN NAR
+2D00..2D25 ; Georgian # L& [38] GEORGIAN SMALL LETTER AN..GEORGIAN SMALL LETTER HOE
+
+# Total code points: 120
+
+# ================================================
+
+1100..1159 ; Hangul # Lo [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH
+115F..11A2 ; Hangul # Lo [68] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG SSANGARAEA
+11A8..11F9 ; Hangul # Lo [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH
+3131..318E ; Hangul # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE
+3200..321E ; Hangul # So [31] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED KOREAN CHARACTER O HU
+3260..327E ; Hangul # So [31] CIRCLED HANGUL KIYEOK..CIRCLED HANGUL IEUNG U
+AC00..D7A3 ; Hangul # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH
+FFA0..FFBE ; Hangul # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH
+FFC2..FFC7 ; Hangul # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E
+FFCA..FFCF ; Hangul # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE
+FFD2..FFD7 ; Hangul # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU
+FFDA..FFDC ; Hangul # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I
+
+# Total code points: 11620
+
+# ================================================
+
+1200..1248 ; Ethiopic # Lo [73] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE QWA
+124A..124D ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE
+1250..1256 ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO
+1258 ; Ethiopic # Lo ETHIOPIC SYLLABLE QHWA
+125A..125D ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE
+1260..1288 ; Ethiopic # Lo [41] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XWA
+128A..128D ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE
+1290..12B0 ; Ethiopic # Lo [33] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KWA
+12B2..12B5 ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE
+12B8..12BE ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO
+12C0 ; Ethiopic # Lo ETHIOPIC SYLLABLE KXWA
+12C2..12C5 ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE
+12C8..12D6 ; Ethiopic # Lo [15] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE PHARYNGEAL O
+12D8..1310 ; Ethiopic # Lo [57] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE GWA
+1312..1315 ; Ethiopic # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE
+1318..135A ; Ethiopic # Lo [67] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE FYA
+135F ; Ethiopic # Mn ETHIOPIC COMBINING GEMINATION MARK
+1360 ; Ethiopic # So ETHIOPIC SECTION MARK
+1361..1368 ; Ethiopic # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR
+1369..137C ; Ethiopic # No [20] ETHIOPIC DIGIT ONE..ETHIOPIC NUMBER TEN THOUSAND
+1380..138F ; Ethiopic # Lo [16] ETHIOPIC SYLLABLE SEBATBEIT MWA..ETHIOPIC SYLLABLE PWE
+1390..1399 ; Ethiopic # So [10] ETHIOPIC TONAL MARK YIZET..ETHIOPIC TONAL MARK KURT
+2D80..2D96 ; Ethiopic # Lo [23] ETHIOPIC SYLLABLE LOA..ETHIOPIC SYLLABLE GGWE
+2DA0..2DA6 ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE SSA..ETHIOPIC SYLLABLE SSO
+2DA8..2DAE ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE CCA..ETHIOPIC SYLLABLE CCO
+2DB0..2DB6 ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE ZZA..ETHIOPIC SYLLABLE ZZO
+2DB8..2DBE ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE CCHA..ETHIOPIC SYLLABLE CCHO
+2DC0..2DC6 ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE QYA..ETHIOPIC SYLLABLE QYO
+2DC8..2DCE ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE KYA..ETHIOPIC SYLLABLE KYO
+2DD0..2DD6 ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE XYA..ETHIOPIC SYLLABLE XYO
+2DD8..2DDE ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE GYA..ETHIOPIC SYLLABLE GYO
+
+# Total code points: 461
+
+# ================================================
+
+13A0..13F4 ; Cherokee # Lo [85] CHEROKEE LETTER A..CHEROKEE LETTER YV
+
+# Total code points: 85
+
+# ================================================
+
+1401..166C ; Canadian_Aboriginal # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA
+166D..166E ; Canadian_Aboriginal # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP
+166F..1676 ; Canadian_Aboriginal # Lo [8] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA
+
+# Total code points: 630
+
+# ================================================
+
+1680 ; Ogham # Zs OGHAM SPACE MARK
+1681..169A ; Ogham # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH
+169B ; Ogham # Ps OGHAM FEATHER MARK
+169C ; Ogham # Pe OGHAM REVERSED FEATHER MARK
+
+# Total code points: 29
+
+# ================================================
+
+16A0..16EA ; Runic # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
+16EE..16F0 ; Runic # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
+
+# Total code points: 78
+
+# ================================================
+
+1780..17B3 ; Khmer # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU
+17B4..17B5 ; Khmer # Cf [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+17B6 ; Khmer # Mc KHMER VOWEL SIGN AA
+17B7..17BD ; Khmer # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA
+17BE..17C5 ; Khmer # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU
+17C6 ; Khmer # Mn KHMER SIGN NIKAHIT
+17C7..17C8 ; Khmer # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU
+17C9..17D3 ; Khmer # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT
+17D4..17D6 ; Khmer # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
+17D7 ; Khmer # Lm KHMER SIGN LEK TOO
+17D8..17DA ; Khmer # Po [3] KHMER SIGN BEYYAL..KHMER SIGN KOOMUUT
+17DB ; Khmer # Sc KHMER CURRENCY SYMBOL RIEL
+17DC ; Khmer # Lo KHMER SIGN AVAKRAHASANYA
+17DD ; Khmer # Mn KHMER SIGN ATTHACAN
+17E0..17E9 ; Khmer # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE
+17F0..17F9 ; Khmer # No [10] KHMER SYMBOL LEK ATTAK SON..KHMER SYMBOL LEK ATTAK PRAM-BUON
+19E0..19FF ; Khmer # So [32] KHMER SYMBOL PATHAMASAT..KHMER SYMBOL DAP-PRAM ROC
+
+# Total code points: 146
+
+# ================================================
+
+1800..1801 ; Mongolian # Po [2] MONGOLIAN BIRGA..MONGOLIAN ELLIPSIS
+1804 ; Mongolian # Po MONGOLIAN COLON
+1806 ; Mongolian # Pd MONGOLIAN TODO SOFT HYPHEN
+1807..180A ; Mongolian # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
+180B..180D ; Mongolian # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+180E ; Mongolian # Zs MONGOLIAN VOWEL SEPARATOR
+1810..1819 ; Mongolian # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
+1820..1842 ; Mongolian # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
+1843 ; Mongolian # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
+1844..1877 ; Mongolian # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA
+1880..18A8 ; Mongolian # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA
+18A9 ; Mongolian # Mn MONGOLIAN LETTER ALI GALI DAGALGA
+18AA ; Mongolian # Lo MONGOLIAN LETTER MANCHU ALI GALI LHA
+
+# Total code points: 153
+
+# ================================================
+
+3041..3096 ; Hiragana # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
+309D..309E ; Hiragana # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
+309F ; Hiragana # Lo HIRAGANA DIGRAPH YORI
+
+# Total code points: 89
+
+# ================================================
+
+30A1..30FA ; Katakana # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO
+30FD..30FE ; Katakana # Lm [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK
+30FF ; Katakana # Lo KATAKANA DIGRAPH KOTO
+31F0..31FF ; Katakana # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+32D0..32FE ; Katakana # So [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO
+3300..3357 ; Katakana # So [88] SQUARE APAATO..SQUARE WATTO
+FF66..FF6F ; Katakana # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU
+FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N
+
+# Total code points: 299
+
+# ================================================
+
+3105..312D ; Bopomofo # Lo [41] BOPOMOFO LETTER B..BOPOMOFO LETTER IH
+31A0..31B7 ; Bopomofo # Lo [24] BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H
+
+# Total code points: 65
+
+# ================================================
+
+2E80..2E99 ; Han # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP
+2E9B..2EF3 ; Han # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE
+2F00..2FD5 ; Han # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE
+3005 ; Han # Lm IDEOGRAPHIC ITERATION MARK
+3007 ; Han # Nl IDEOGRAPHIC NUMBER ZERO
+3021..3029 ; Han # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
+3038..303A ; Han # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
+303B ; Han # Lm VERTICAL IDEOGRAPHIC ITERATION MARK
+3400..4DB5 ; Han # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
+4E00..9FC3 ; Han # Lo [20932] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FC3
+F900..FA2D ; Han # Lo [302] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA2D
+FA30..FA6A ; Han # Lo [59] CJK COMPATIBILITY IDEOGRAPH-FA30..CJK COMPATIBILITY IDEOGRAPH-FA6A
+FA70..FAD9 ; Han # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
+20000..2A6D6 ; Han # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
+2F800..2FA1D ; Han # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
+
+# Total code points: 71578
+
+# ================================================
+
+A000..A014 ; Yi # Lo [21] YI SYLLABLE IT..YI SYLLABLE E
+A015 ; Yi # Lm YI SYLLABLE WU
+A016..A48C ; Yi # Lo [1143] YI SYLLABLE BIT..YI SYLLABLE YYR
+A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE
+
+# Total code points: 1220
+
+# ================================================
+
+10300..1031E ; Old_Italic # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU
+10320..10323 ; Old_Italic # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
+
+# Total code points: 35
+
+# ================================================
+
+10330..10340 ; Gothic # Lo [17] GOTHIC LETTER AHSA..GOTHIC LETTER PAIRTHRA
+10341 ; Gothic # Nl GOTHIC LETTER NINETY
+10342..10349 ; Gothic # Lo [8] GOTHIC LETTER RAIDA..GOTHIC LETTER OTHAL
+1034A ; Gothic # Nl GOTHIC LETTER NINE HUNDRED
+
+# Total code points: 27
+
+# ================================================
+
+10400..1044F ; Deseret # L& [80] DESERET CAPITAL LETTER LONG I..DESERET SMALL LETTER EW
+
+# Total code points: 80
+
+# ================================================
+
+0300..036F ; Inherited # Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X
+064B..0655 ; Inherited # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW
+0670 ; Inherited # Mn ARABIC LETTER SUPERSCRIPT ALEF
+0951..0952 ; Inherited # Mn [2] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI STRESS SIGN ANUDATTA
+1DC0..1DE6 ; Inherited # Mn [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z
+1DFE..1DFF ; Inherited # Mn [2] COMBINING LEFT ARROWHEAD ABOVE..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
+200C..200D ; Inherited # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER
+20D0..20DC ; Inherited # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
+20DD..20E0 ; Inherited # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH
+20E1 ; Inherited # Mn COMBINING LEFT RIGHT ARROW ABOVE
+20E2..20E4 ; Inherited # Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE
+20E5..20F0 ; Inherited # Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE
+302A..302F ; Inherited # Mn [6] IDEOGRAPHIC LEVEL TONE MARK..HANGUL DOUBLE DOT TONE MARK
+3099..309A ; Inherited # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
+FE00..FE0F ; Inherited # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+FE20..FE26 ; Inherited # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
+101FD ; Inherited # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
+1D167..1D169 ; Inherited # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
+1D17B..1D182 ; Inherited # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
+1D185..1D18B ; Inherited # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
+1D1AA..1D1AD ; Inherited # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
+E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+
+# Total code points: 496
+
+# ================================================
+
+1700..170C ; Tagalog # Lo [13] TAGALOG LETTER A..TAGALOG LETTER YA
+170E..1711 ; Tagalog # Lo [4] TAGALOG LETTER LA..TAGALOG LETTER HA
+1712..1714 ; Tagalog # Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA
+
+# Total code points: 20
+
+# ================================================
+
+1720..1731 ; Hanunoo # Lo [18] HANUNOO LETTER A..HANUNOO LETTER HA
+1732..1734 ; Hanunoo # Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD
+
+# Total code points: 21
+
+# ================================================
+
+1740..1751 ; Buhid # Lo [18] BUHID LETTER A..BUHID LETTER HA
+1752..1753 ; Buhid # Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U
+
+# Total code points: 20
+
+# ================================================
+
+1760..176C ; Tagbanwa # Lo [13] TAGBANWA LETTER A..TAGBANWA LETTER YA
+176E..1770 ; Tagbanwa # Lo [3] TAGBANWA LETTER LA..TAGBANWA LETTER SA
+1772..1773 ; Tagbanwa # Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U
+
+# Total code points: 18
+
+# ================================================
+
+1900..191C ; Limbu # Lo [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA
+1920..1922 ; Limbu # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
+1923..1926 ; Limbu # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
+1927..1928 ; Limbu # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
+1929..192B ; Limbu # Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA
+1930..1931 ; Limbu # Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA
+1932 ; Limbu # Mn LIMBU SMALL LETTER ANUSVARA
+1933..1938 ; Limbu # Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA
+1939..193B ; Limbu # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
+1940 ; Limbu # So LIMBU SIGN LOO
+1944..1945 ; Limbu # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
+1946..194F ; Limbu # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
+
+# Total code points: 66
+
+# ================================================
+
+1950..196D ; Tai_Le # Lo [30] TAI LE LETTER KA..TAI LE LETTER AI
+1970..1974 ; Tai_Le # Lo [5] TAI LE LETTER TONE-2..TAI LE LETTER TONE-6
+
+# Total code points: 35
+
+# ================================================
+
+10000..1000B ; Linear_B # Lo [12] LINEAR B SYLLABLE B008 A..LINEAR B SYLLABLE B046 JE
+1000D..10026 ; Linear_B # Lo [26] LINEAR B SYLLABLE B036 JO..LINEAR B SYLLABLE B032 QO
+10028..1003A ; Linear_B # Lo [19] LINEAR B SYLLABLE B060 RA..LINEAR B SYLLABLE B042 WO
+1003C..1003D ; Linear_B # Lo [2] LINEAR B SYLLABLE B017 ZA..LINEAR B SYLLABLE B074 ZE
+1003F..1004D ; Linear_B # Lo [15] LINEAR B SYLLABLE B020 ZO..LINEAR B SYLLABLE B091 TWO
+10050..1005D ; Linear_B # Lo [14] LINEAR B SYMBOL B018..LINEAR B SYMBOL B089
+10080..100FA ; Linear_B # Lo [123] LINEAR B IDEOGRAM B100 MAN..LINEAR B IDEOGRAM VESSEL B305
+
+# Total code points: 211
+
+# ================================================
+
+10380..1039D ; Ugaritic # Lo [30] UGARITIC LETTER ALPA..UGARITIC LETTER SSU
+1039F ; Ugaritic # Po UGARITIC WORD DIVIDER
+
+# Total code points: 31
+
+# ================================================
+
+10450..1047F ; Shavian # Lo [48] SHAVIAN LETTER PEEP..SHAVIAN LETTER YEW
+
+# Total code points: 48
+
+# ================================================
+
+10480..1049D ; Osmanya # Lo [30] OSMANYA LETTER ALEF..OSMANYA LETTER OO
+104A0..104A9 ; Osmanya # Nd [10] OSMANYA DIGIT ZERO..OSMANYA DIGIT NINE
+
+# Total code points: 40
+
+# ================================================
+
+10800..10805 ; Cypriot # Lo [6] CYPRIOT SYLLABLE A..CYPRIOT SYLLABLE JA
+10808 ; Cypriot # Lo CYPRIOT SYLLABLE JO
+1080A..10835 ; Cypriot # Lo [44] CYPRIOT SYLLABLE KA..CYPRIOT SYLLABLE WO
+10837..10838 ; Cypriot # Lo [2] CYPRIOT SYLLABLE XA..CYPRIOT SYLLABLE XE
+1083C ; Cypriot # Lo CYPRIOT SYLLABLE ZA
+1083F ; Cypriot # Lo CYPRIOT SYLLABLE ZO
+
+# Total code points: 55
+
+# ================================================
+
+2800..28FF ; Braille # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678
+
+# Total code points: 256
+
+# ================================================
+
+1A00..1A16 ; Buginese # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
+1A17..1A18 ; Buginese # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
+1A19..1A1B ; Buginese # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
+1A1E..1A1F ; Buginese # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
+
+# Total code points: 30
+
+# ================================================
+
+03E2..03EF ; Coptic # L& [14] COPTIC CAPITAL LETTER SHEI..COPTIC SMALL LETTER DEI
+2C80..2CE4 ; Coptic # L& [101] COPTIC CAPITAL LETTER ALFA..COPTIC SYMBOL KAI
+2CE5..2CEA ; Coptic # So [6] COPTIC SYMBOL MI RO..COPTIC SYMBOL SHIMA SIMA
+2CF9..2CFC ; Coptic # Po [4] COPTIC OLD NUBIAN FULL STOP..COPTIC OLD NUBIAN VERSE DIVIDER
+2CFD ; Coptic # No COPTIC FRACTION ONE HALF
+2CFE..2CFF ; Coptic # Po [2] COPTIC FULL STOP..COPTIC MORPHOLOGICAL DIVIDER
+
+# Total code points: 128
+
+# ================================================
+
+1980..19A9 ; New_Tai_Lue # Lo [42] NEW TAI LUE LETTER HIGH QA..NEW TAI LUE LETTER LOW XVA
+19B0..19C0 ; New_Tai_Lue # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY
+19C1..19C7 ; New_Tai_Lue # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B
+19C8..19C9 ; New_Tai_Lue # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2
+19D0..19D9 ; New_Tai_Lue # Nd [10] NEW TAI LUE DIGIT ZERO..NEW TAI LUE DIGIT NINE
+19DE..19DF ; New_Tai_Lue # Po [2] NEW TAI LUE SIGN LAE..NEW TAI LUE SIGN LAEV
+
+# Total code points: 80
+
+# ================================================
+
+2C00..2C2E ; Glagolitic # L& [47] GLAGOLITIC CAPITAL LETTER AZU..GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C30..2C5E ; Glagolitic # L& [47] GLAGOLITIC SMALL LETTER AZU..GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+
+# Total code points: 94
+
+# ================================================
+
+2D30..2D65 ; Tifinagh # Lo [54] TIFINAGH LETTER YA..TIFINAGH LETTER YAZZ
+2D6F ; Tifinagh # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK
+
+# Total code points: 55
+
+# ================================================
+
+A800..A801 ; Syloti_Nagri # Lo [2] SYLOTI NAGRI LETTER A..SYLOTI NAGRI LETTER I
+A802 ; Syloti_Nagri # Mn SYLOTI NAGRI SIGN DVISVARA
+A803..A805 ; Syloti_Nagri # Lo [3] SYLOTI NAGRI LETTER U..SYLOTI NAGRI LETTER O
+A806 ; Syloti_Nagri # Mn SYLOTI NAGRI SIGN HASANTA
+A807..A80A ; Syloti_Nagri # Lo [4] SYLOTI NAGRI LETTER KO..SYLOTI NAGRI LETTER GHO
+A80B ; Syloti_Nagri # Mn SYLOTI NAGRI SIGN ANUSVARA
+A80C..A822 ; Syloti_Nagri # Lo [23] SYLOTI NAGRI LETTER CO..SYLOTI NAGRI LETTER HO
+A823..A824 ; Syloti_Nagri # Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I
+A825..A826 ; Syloti_Nagri # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
+A827 ; Syloti_Nagri # Mc SYLOTI NAGRI VOWEL SIGN OO
+A828..A82B ; Syloti_Nagri # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI POETRY MARK-4
+
+# Total code points: 44
+
+# ================================================
+
+103A0..103C3 ; Old_Persian # Lo [36] OLD PERSIAN SIGN A..OLD PERSIAN SIGN HA
+103C8..103CF ; Old_Persian # Lo [8] OLD PERSIAN SIGN AURAMAZDAA..OLD PERSIAN SIGN BUUMISH
+103D0 ; Old_Persian # Po OLD PERSIAN WORD DIVIDER
+103D1..103D5 ; Old_Persian # Nl [5] OLD PERSIAN NUMBER ONE..OLD PERSIAN NUMBER HUNDRED
+
+# Total code points: 50
+
+# ================================================
+
+10A00 ; Kharoshthi # Lo KHAROSHTHI LETTER A
+10A01..10A03 ; Kharoshthi # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
+10A05..10A06 ; Kharoshthi # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
+10A0C..10A0F ; Kharoshthi # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10A10..10A13 ; Kharoshthi # Lo [4] KHAROSHTHI LETTER KA..KHAROSHTHI LETTER GHA
+10A15..10A17 ; Kharoshthi # Lo [3] KHAROSHTHI LETTER CA..KHAROSHTHI LETTER JA
+10A19..10A33 ; Kharoshthi # Lo [27] KHAROSHTHI LETTER NYA..KHAROSHTHI LETTER TTTHA
+10A38..10A3A ; Kharoshthi # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
+10A3F ; Kharoshthi # Mn KHAROSHTHI VIRAMA
+10A40..10A47 ; Kharoshthi # No [8] KHAROSHTHI DIGIT ONE..KHAROSHTHI NUMBER ONE THOUSAND
+10A50..10A58 ; Kharoshthi # Po [9] KHAROSHTHI PUNCTUATION DOT..KHAROSHTHI PUNCTUATION LINES
+
+# Total code points: 65
+
+# ================================================
+
+1B00..1B03 ; Balinese # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
+1B04 ; Balinese # Mc BALINESE SIGN BISAH
+1B05..1B33 ; Balinese # Lo [47] BALINESE LETTER AKARA..BALINESE LETTER HA
+1B34 ; Balinese # Mn BALINESE SIGN REREKAN
+1B35 ; Balinese # Mc BALINESE VOWEL SIGN TEDUNG
+1B36..1B3A ; Balinese # Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA
+1B3B ; Balinese # Mc BALINESE VOWEL SIGN RA REPA TEDUNG
+1B3C ; Balinese # Mn BALINESE VOWEL SIGN LA LENGA
+1B3D..1B41 ; Balinese # Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG
+1B42 ; Balinese # Mn BALINESE VOWEL SIGN PEPET
+1B43..1B44 ; Balinese # Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG
+1B45..1B4B ; Balinese # Lo [7] BALINESE LETTER KAF SASAK..BALINESE LETTER ASYURA SASAK
+1B50..1B59 ; Balinese # Nd [10] BALINESE DIGIT ZERO..BALINESE DIGIT NINE
+1B5A..1B60 ; Balinese # Po [7] BALINESE PANTI..BALINESE PAMENENG
+1B61..1B6A ; Balinese # So [10] BALINESE MUSICAL SYMBOL DONG..BALINESE MUSICAL SYMBOL DANG GEDE
+1B6B..1B73 ; Balinese # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
+1B74..1B7C ; Balinese # So [9] BALINESE MUSICAL SYMBOL RIGHT-HAND OPEN DUG..BALINESE MUSICAL SYMBOL LEFT-HAND OPEN PING
+
+# Total code points: 121
+
+# ================================================
+
+12000..1236E ; Cuneiform # Lo [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM
+12400..12462 ; Cuneiform # Nl [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER
+12470..12473 ; Cuneiform # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON
+
+# Total code points: 982
+
+# ================================================
+
+10900..10915 ; Phoenician # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
+10916..10919 ; Phoenician # No [4] PHOENICIAN NUMBER ONE..PHOENICIAN NUMBER ONE HUNDRED
+1091F ; Phoenician # Po PHOENICIAN WORD SEPARATOR
+
+# Total code points: 27
+
+# ================================================
+
+A840..A873 ; Phags_Pa # Lo [52] PHAGS-PA LETTER KA..PHAGS-PA LETTER CANDRABINDU
+A874..A877 ; Phags_Pa # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOUBLE SHAD
+
+# Total code points: 56
+
+# ================================================
+
+07C0..07C9 ; Nko # Nd [10] NKO DIGIT ZERO..NKO DIGIT NINE
+07CA..07EA ; Nko # Lo [33] NKO LETTER A..NKO LETTER JONA RA
+07EB..07F3 ; Nko # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07F4..07F5 ; Nko # Lm [2] NKO HIGH TONE APOSTROPHE..NKO LOW TONE APOSTROPHE
+07F6 ; Nko # So NKO SYMBOL OO DENNEN
+07F7..07F9 ; Nko # Po [3] NKO SYMBOL GBAKURUNEN..NKO EXCLAMATION MARK
+07FA ; Nko # Lm NKO LAJANYALAN
+
+# Total code points: 59
+
+# ================================================
+
+1B80..1B81 ; Sundanese # Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR
+1B82 ; Sundanese # Mc SUNDANESE SIGN PANGWISAD
+1B83..1BA0 ; Sundanese # Lo [30] SUNDANESE LETTER A..SUNDANESE LETTER HA
+1BA1 ; Sundanese # Mc SUNDANESE CONSONANT SIGN PAMINGKAL
+1BA2..1BA5 ; Sundanese # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
+1BA6..1BA7 ; Sundanese # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
+1BA8..1BA9 ; Sundanese # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
+1BAA ; Sundanese # Mc SUNDANESE SIGN PAMAAEH
+1BAE..1BAF ; Sundanese # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
+1BB0..1BB9 ; Sundanese # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
+
+# Total code points: 55
+
+# ================================================
+
+1C00..1C23 ; Lepcha # Lo [36] LEPCHA LETTER KA..LEPCHA LETTER A
+1C24..1C2B ; Lepcha # Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU
+1C2C..1C33 ; Lepcha # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
+1C34..1C35 ; Lepcha # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
+1C36..1C37 ; Lepcha # Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA
+1C3B..1C3F ; Lepcha # Po [5] LEPCHA PUNCTUATION TA-ROL..LEPCHA PUNCTUATION TSHOOK
+1C40..1C49 ; Lepcha # Nd [10] LEPCHA DIGIT ZERO..LEPCHA DIGIT NINE
+1C4D..1C4F ; Lepcha # Lo [3] LEPCHA LETTER TTA..LEPCHA LETTER DDA
+
+# Total code points: 74
+
+# ================================================
+
+1C50..1C59 ; Ol_Chiki # Nd [10] OL CHIKI DIGIT ZERO..OL CHIKI DIGIT NINE
+1C5A..1C77 ; Ol_Chiki # Lo [30] OL CHIKI LETTER LA..OL CHIKI LETTER OH
+1C78..1C7D ; Ol_Chiki # Lm [6] OL CHIKI MU TTUDDAG..OL CHIKI AHAD
+1C7E..1C7F ; Ol_Chiki # Po [2] OL CHIKI PUNCTUATION MUCAAD..OL CHIKI PUNCTUATION DOUBLE MUCAAD
+
+# Total code points: 48
+
+# ================================================
+
+A500..A60B ; Vai # Lo [268] VAI SYLLABLE EE..VAI SYLLABLE NG
+A60C ; Vai # Lm VAI SYLLABLE LENGTHENER
+A60D..A60F ; Vai # Po [3] VAI COMMA..VAI QUESTION MARK
+A610..A61F ; Vai # Lo [16] VAI SYLLABLE NDOLE FA..VAI SYMBOL JONG
+A620..A629 ; Vai # Nd [10] VAI DIGIT ZERO..VAI DIGIT NINE
+A62A..A62B ; Vai # Lo [2] VAI SYLLABLE NDOLE MA..VAI SYLLABLE NDOLE DO
+
+# Total code points: 300
+
+# ================================================
+
+A880..A881 ; Saurashtra # Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA
+A882..A8B3 ; Saurashtra # Lo [50] SAURASHTRA LETTER A..SAURASHTRA LETTER LLA
+A8B4..A8C3 ; Saurashtra # Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU
+A8C4 ; Saurashtra # Mn SAURASHTRA SIGN VIRAMA
+A8CE..A8CF ; Saurashtra # Po [2] SAURASHTRA DANDA..SAURASHTRA DOUBLE DANDA
+A8D0..A8D9 ; Saurashtra # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NINE
+
+# Total code points: 81
+
+# ================================================
+
+A900..A909 ; Kayah_Li # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
+A90A..A925 ; Kayah_Li # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
+A926..A92D ; Kayah_Li # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
+A92E..A92F ; Kayah_Li # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
+
+# Total code points: 48
+
+# ================================================
+
+A930..A946 ; Rejang # Lo [23] REJANG LETTER KA..REJANG LETTER A
+A947..A951 ; Rejang # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
+A952..A953 ; Rejang # Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA
+A95F ; Rejang # Po REJANG SECTION MARK
+
+# Total code points: 37
+
+# ================================================
+
+10280..1029C ; Lycian # Lo [29] LYCIAN LETTER A..LYCIAN LETTER X
+
+# Total code points: 29
+
+# ================================================
+
+102A0..102D0 ; Carian # Lo [49] CARIAN LETTER A..CARIAN LETTER UUU3
+
+# Total code points: 49
+
+# ================================================
+
+10920..10939 ; Lydian # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+1093F ; Lydian # Po LYDIAN TRIANGULAR MARK
+
+# Total code points: 27
+
+# ================================================
+
+AA00..AA28 ; Cham # Lo [41] CHAM LETTER A..CHAM LETTER HA
+AA29..AA2E ; Cham # Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE
+AA2F..AA30 ; Cham # Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI
+AA31..AA32 ; Cham # Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE
+AA33..AA34 ; Cham # Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA
+AA35..AA36 ; Cham # Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA
+AA40..AA42 ; Cham # Lo [3] CHAM LETTER FINAL K..CHAM LETTER FINAL NG
+AA43 ; Cham # Mn CHAM CONSONANT SIGN FINAL NG
+AA44..AA4B ; Cham # Lo [8] CHAM LETTER FINAL CH..CHAM LETTER FINAL SS
+AA4C ; Cham # Mn CHAM CONSONANT SIGN FINAL M
+AA4D ; Cham # Mc CHAM CONSONANT SIGN FINAL H
+AA50..AA59 ; Cham # Nd [10] CHAM DIGIT ZERO..CHAM DIGIT NINE
+AA5C..AA5F ; Cham # Po [4] CHAM PUNCTUATION SPIRAL..CHAM PUNCTUATION TRIPLE DANDA
+
+# Total code points: 83
+
+# EOF
diff --git a/third_party/harfbuzz/contrib/tables/category-parse.py b/third_party/harfbuzz/contrib/tables/category-parse.py
new file mode 100644
index 0000000..6818c1d
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/category-parse.py
@@ -0,0 +1,70 @@
+import sys
+from unicode_parse_common import *
+
+# http://www.unicode.org/Public/5.1.0/ucd/extracted/DerivedGeneralCategory.txt
+
+category_to_harfbuzz = {
+ 'Mn': 'HB_Mark_NonSpacing',
+ 'Mc': 'HB_Mark_SpacingCombining',
+ 'Me': 'HB_Mark_Enclosing',
+
+ 'Nd': 'HB_Number_DecimalDigit',
+ 'Nl': 'HB_Number_Letter',
+ 'No': 'HB_Number_Other',
+
+ 'Zs': 'HB_Separator_Space',
+ 'Zl': 'HB_Separator_Line',
+ 'Zp': 'HB_Separator_Paragraph',
+
+ 'Cc': 'HB_Other_Control',
+ 'Cf': 'HB_Other_Format',
+ 'Cs': 'HB_Other_Surrogate',
+ 'Co': 'HB_Other_PrivateUse',
+ 'Cn': 'HB_Other_NotAssigned',
+
+ 'Lu': 'HB_Letter_Uppercase',
+ 'Ll': 'HB_Letter_Lowercase',
+ 'Lt': 'HB_Letter_Titlecase',
+ 'Lm': 'HB_Letter_Modifier',
+ 'Lo': 'HB_Letter_Other',
+
+ 'Pc': 'HB_Punctuation_Connector',
+ 'Pd': 'HB_Punctuation_Dash',
+ 'Ps': 'HB_Punctuation_Open',
+ 'Pe': 'HB_Punctuation_Close',
+ 'Pi': 'HB_Punctuation_InitialQuote',
+ 'Pf': 'HB_Punctuation_FinalQuote',
+ 'Po': 'HB_Punctuation_Other',
+
+ 'Sm': 'HB_Symbol_Math',
+ 'Sc': 'HB_Symbol_Currency',
+ 'Sk': 'HB_Symbol_Modifier',
+ 'So': 'HB_Symbol_Other',
+}
+
+def main(infile, outfile):
+ ranges = unicode_file_parse(infile, category_to_harfbuzz)
+ ranges = sort_and_merge(ranges)
+
+ print >>outfile, '// Generated from Unicode script tables\n'
+ print >>outfile, '#ifndef CATEGORY_PROPERTIES_H_'
+ print >>outfile, '#define CATEGORY_PROPERTIES_H_\n'
+ print >>outfile, '#include <stdint.h>'
+ print >>outfile, '#include "harfbuzz-external.h"\n'
+ print >>outfile, 'struct category_property {'
+ print >>outfile, ' uint32_t range_start;'
+ print >>outfile, ' uint32_t range_end;'
+ print >>outfile, ' HB_CharCategory category;'
+ print >>outfile, '};\n'
+ print >>outfile, 'static const struct category_property category_properties[] = {'
+ for (start, end, value) in ranges:
+ print >>outfile, ' {0x%x, 0x%x, %s},' % (start, end, value)
+ print >>outfile, '};\n'
+ print >>outfile, 'static const unsigned category_properties_count = %d;\n' % len(ranges)
+ print >>outfile, '#endif // CATEGORY_PROPERTIES_H_'
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print 'Usage: %s <input .txt> <output .h>' % sys.argv[0]
+ else:
+ main(file(sys.argv[1], 'r'), file(sys.argv[2], 'w+'))
diff --git a/third_party/harfbuzz/contrib/tables/category-properties.h b/third_party/harfbuzz/contrib/tables/category-properties.h
new file mode 100644
index 0000000..3b7c7ca
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/category-properties.h
@@ -0,0 +1,2869 @@
+// Generated from Unicode script tables
+
+#ifndef CATEGORY_PROPERTIES_H_
+#define CATEGORY_PROPERTIES_H_
+
+#include <stdint.h>
+#include "harfbuzz-external.h"
+
+struct category_property {
+ uint32_t range_start;
+ uint32_t range_end;
+ HB_CharCategory category;
+};
+
+static const struct category_property category_properties[] = {
+ {0x0, 0x1f, HB_Other_Control},
+ {0x20, 0x20, HB_Separator_Space},
+ {0x21, 0x23, HB_Punctuation_Other},
+ {0x24, 0x24, HB_Symbol_Currency},
+ {0x25, 0x27, HB_Punctuation_Other},
+ {0x28, 0x28, HB_Punctuation_Open},
+ {0x29, 0x29, HB_Punctuation_Close},
+ {0x2a, 0x2a, HB_Punctuation_Other},
+ {0x2b, 0x2b, HB_Symbol_Math},
+ {0x2c, 0x2c, HB_Punctuation_Other},
+ {0x2d, 0x2d, HB_Punctuation_Dash},
+ {0x2e, 0x2f, HB_Punctuation_Other},
+ {0x30, 0x39, HB_Number_DecimalDigit},
+ {0x3a, 0x3b, HB_Punctuation_Other},
+ {0x3c, 0x3e, HB_Symbol_Math},
+ {0x3f, 0x40, HB_Punctuation_Other},
+ {0x41, 0x5a, HB_Letter_Uppercase},
+ {0x5b, 0x5b, HB_Punctuation_Open},
+ {0x5c, 0x5c, HB_Punctuation_Other},
+ {0x5d, 0x5d, HB_Punctuation_Close},
+ {0x5e, 0x5e, HB_Symbol_Modifier},
+ {0x5f, 0x5f, HB_Punctuation_Connector},
+ {0x60, 0x60, HB_Symbol_Modifier},
+ {0x61, 0x7a, HB_Letter_Lowercase},
+ {0x7b, 0x7b, HB_Punctuation_Open},
+ {0x7c, 0x7c, HB_Symbol_Math},
+ {0x7d, 0x7d, HB_Punctuation_Close},
+ {0x7e, 0x7e, HB_Symbol_Math},
+ {0x7f, 0x9f, HB_Other_Control},
+ {0xa0, 0xa0, HB_Separator_Space},
+ {0xa1, 0xa1, HB_Punctuation_Other},
+ {0xa2, 0xa5, HB_Symbol_Currency},
+ {0xa6, 0xa7, HB_Symbol_Other},
+ {0xa8, 0xa8, HB_Symbol_Modifier},
+ {0xa9, 0xa9, HB_Symbol_Other},
+ {0xaa, 0xaa, HB_Letter_Lowercase},
+ {0xab, 0xab, HB_Punctuation_InitialQuote},
+ {0xac, 0xac, HB_Symbol_Math},
+ {0xad, 0xad, HB_Other_Format},
+ {0xae, 0xae, HB_Symbol_Other},
+ {0xaf, 0xaf, HB_Symbol_Modifier},
+ {0xb0, 0xb0, HB_Symbol_Other},
+ {0xb1, 0xb1, HB_Symbol_Math},
+ {0xb2, 0xb3, HB_Number_Other},
+ {0xb4, 0xb4, HB_Symbol_Modifier},
+ {0xb5, 0xb5, HB_Letter_Lowercase},
+ {0xb6, 0xb6, HB_Symbol_Other},
+ {0xb7, 0xb7, HB_Punctuation_Other},
+ {0xb8, 0xb8, HB_Symbol_Modifier},
+ {0xb9, 0xb9, HB_Number_Other},
+ {0xba, 0xba, HB_Letter_Lowercase},
+ {0xbb, 0xbb, HB_Punctuation_FinalQuote},
+ {0xbc, 0xbe, HB_Number_Other},
+ {0xbf, 0xbf, HB_Punctuation_Other},
+ {0xc0, 0xd6, HB_Letter_Uppercase},
+ {0xd7, 0xd7, HB_Symbol_Math},
+ {0xd8, 0xde, HB_Letter_Uppercase},
+ {0xdf, 0xf6, HB_Letter_Lowercase},
+ {0xf7, 0xf7, HB_Symbol_Math},
+ {0xf8, 0xff, HB_Letter_Lowercase},
+ {0x100, 0x100, HB_Letter_Uppercase},
+ {0x101, 0x101, HB_Letter_Lowercase},
+ {0x102, 0x102, HB_Letter_Uppercase},
+ {0x103, 0x103, HB_Letter_Lowercase},
+ {0x104, 0x104, HB_Letter_Uppercase},
+ {0x105, 0x105, HB_Letter_Lowercase},
+ {0x106, 0x106, HB_Letter_Uppercase},
+ {0x107, 0x107, HB_Letter_Lowercase},
+ {0x108, 0x108, HB_Letter_Uppercase},
+ {0x109, 0x109, HB_Letter_Lowercase},
+ {0x10a, 0x10a, HB_Letter_Uppercase},
+ {0x10b, 0x10b, HB_Letter_Lowercase},
+ {0x10c, 0x10c, HB_Letter_Uppercase},
+ {0x10d, 0x10d, HB_Letter_Lowercase},
+ {0x10e, 0x10e, HB_Letter_Uppercase},
+ {0x10f, 0x10f, HB_Letter_Lowercase},
+ {0x110, 0x110, HB_Letter_Uppercase},
+ {0x111, 0x111, HB_Letter_Lowercase},
+ {0x112, 0x112, HB_Letter_Uppercase},
+ {0x113, 0x113, HB_Letter_Lowercase},
+ {0x114, 0x114, HB_Letter_Uppercase},
+ {0x115, 0x115, HB_Letter_Lowercase},
+ {0x116, 0x116, HB_Letter_Uppercase},
+ {0x117, 0x117, HB_Letter_Lowercase},
+ {0x118, 0x118, HB_Letter_Uppercase},
+ {0x119, 0x119, HB_Letter_Lowercase},
+ {0x11a, 0x11a, HB_Letter_Uppercase},
+ {0x11b, 0x11b, HB_Letter_Lowercase},
+ {0x11c, 0x11c, HB_Letter_Uppercase},
+ {0x11d, 0x11d, HB_Letter_Lowercase},
+ {0x11e, 0x11e, HB_Letter_Uppercase},
+ {0x11f, 0x11f, HB_Letter_Lowercase},
+ {0x120, 0x120, HB_Letter_Uppercase},
+ {0x121, 0x121, HB_Letter_Lowercase},
+ {0x122, 0x122, HB_Letter_Uppercase},
+ {0x123, 0x123, HB_Letter_Lowercase},
+ {0x124, 0x124, HB_Letter_Uppercase},
+ {0x125, 0x125, HB_Letter_Lowercase},
+ {0x126, 0x126, HB_Letter_Uppercase},
+ {0x127, 0x127, HB_Letter_Lowercase},
+ {0x128, 0x128, HB_Letter_Uppercase},
+ {0x129, 0x129, HB_Letter_Lowercase},
+ {0x12a, 0x12a, HB_Letter_Uppercase},
+ {0x12b, 0x12b, HB_Letter_Lowercase},
+ {0x12c, 0x12c, HB_Letter_Uppercase},
+ {0x12d, 0x12d, HB_Letter_Lowercase},
+ {0x12e, 0x12e, HB_Letter_Uppercase},
+ {0x12f, 0x12f, HB_Letter_Lowercase},
+ {0x130, 0x130, HB_Letter_Uppercase},
+ {0x131, 0x131, HB_Letter_Lowercase},
+ {0x132, 0x132, HB_Letter_Uppercase},
+ {0x133, 0x133, HB_Letter_Lowercase},
+ {0x134, 0x134, HB_Letter_Uppercase},
+ {0x135, 0x135, HB_Letter_Lowercase},
+ {0x136, 0x136, HB_Letter_Uppercase},
+ {0x137, 0x138, HB_Letter_Lowercase},
+ {0x139, 0x139, HB_Letter_Uppercase},
+ {0x13a, 0x13a, HB_Letter_Lowercase},
+ {0x13b, 0x13b, HB_Letter_Uppercase},
+ {0x13c, 0x13c, HB_Letter_Lowercase},
+ {0x13d, 0x13d, HB_Letter_Uppercase},
+ {0x13e, 0x13e, HB_Letter_Lowercase},
+ {0x13f, 0x13f, HB_Letter_Uppercase},
+ {0x140, 0x140, HB_Letter_Lowercase},
+ {0x141, 0x141, HB_Letter_Uppercase},
+ {0x142, 0x142, HB_Letter_Lowercase},
+ {0x143, 0x143, HB_Letter_Uppercase},
+ {0x144, 0x144, HB_Letter_Lowercase},
+ {0x145, 0x145, HB_Letter_Uppercase},
+ {0x146, 0x146, HB_Letter_Lowercase},
+ {0x147, 0x147, HB_Letter_Uppercase},
+ {0x148, 0x149, HB_Letter_Lowercase},
+ {0x14a, 0x14a, HB_Letter_Uppercase},
+ {0x14b, 0x14b, HB_Letter_Lowercase},
+ {0x14c, 0x14c, HB_Letter_Uppercase},
+ {0x14d, 0x14d, HB_Letter_Lowercase},
+ {0x14e, 0x14e, HB_Letter_Uppercase},
+ {0x14f, 0x14f, HB_Letter_Lowercase},
+ {0x150, 0x150, HB_Letter_Uppercase},
+ {0x151, 0x151, HB_Letter_Lowercase},
+ {0x152, 0x152, HB_Letter_Uppercase},
+ {0x153, 0x153, HB_Letter_Lowercase},
+ {0x154, 0x154, HB_Letter_Uppercase},
+ {0x155, 0x155, HB_Letter_Lowercase},
+ {0x156, 0x156, HB_Letter_Uppercase},
+ {0x157, 0x157, HB_Letter_Lowercase},
+ {0x158, 0x158, HB_Letter_Uppercase},
+ {0x159, 0x159, HB_Letter_Lowercase},
+ {0x15a, 0x15a, HB_Letter_Uppercase},
+ {0x15b, 0x15b, HB_Letter_Lowercase},
+ {0x15c, 0x15c, HB_Letter_Uppercase},
+ {0x15d, 0x15d, HB_Letter_Lowercase},
+ {0x15e, 0x15e, HB_Letter_Uppercase},
+ {0x15f, 0x15f, HB_Letter_Lowercase},
+ {0x160, 0x160, HB_Letter_Uppercase},
+ {0x161, 0x161, HB_Letter_Lowercase},
+ {0x162, 0x162, HB_Letter_Uppercase},
+ {0x163, 0x163, HB_Letter_Lowercase},
+ {0x164, 0x164, HB_Letter_Uppercase},
+ {0x165, 0x165, HB_Letter_Lowercase},
+ {0x166, 0x166, HB_Letter_Uppercase},
+ {0x167, 0x167, HB_Letter_Lowercase},
+ {0x168, 0x168, HB_Letter_Uppercase},
+ {0x169, 0x169, HB_Letter_Lowercase},
+ {0x16a, 0x16a, HB_Letter_Uppercase},
+ {0x16b, 0x16b, HB_Letter_Lowercase},
+ {0x16c, 0x16c, HB_Letter_Uppercase},
+ {0x16d, 0x16d, HB_Letter_Lowercase},
+ {0x16e, 0x16e, HB_Letter_Uppercase},
+ {0x16f, 0x16f, HB_Letter_Lowercase},
+ {0x170, 0x170, HB_Letter_Uppercase},
+ {0x171, 0x171, HB_Letter_Lowercase},
+ {0x172, 0x172, HB_Letter_Uppercase},
+ {0x173, 0x173, HB_Letter_Lowercase},
+ {0x174, 0x174, HB_Letter_Uppercase},
+ {0x175, 0x175, HB_Letter_Lowercase},
+ {0x176, 0x176, HB_Letter_Uppercase},
+ {0x177, 0x177, HB_Letter_Lowercase},
+ {0x178, 0x179, HB_Letter_Uppercase},
+ {0x17a, 0x17a, HB_Letter_Lowercase},
+ {0x17b, 0x17b, HB_Letter_Uppercase},
+ {0x17c, 0x17c, HB_Letter_Lowercase},
+ {0x17d, 0x17d, HB_Letter_Uppercase},
+ {0x17e, 0x180, HB_Letter_Lowercase},
+ {0x181, 0x182, HB_Letter_Uppercase},
+ {0x183, 0x183, HB_Letter_Lowercase},
+ {0x184, 0x184, HB_Letter_Uppercase},
+ {0x185, 0x185, HB_Letter_Lowercase},
+ {0x186, 0x187, HB_Letter_Uppercase},
+ {0x188, 0x188, HB_Letter_Lowercase},
+ {0x189, 0x18b, HB_Letter_Uppercase},
+ {0x18c, 0x18d, HB_Letter_Lowercase},
+ {0x18e, 0x191, HB_Letter_Uppercase},
+ {0x192, 0x192, HB_Letter_Lowercase},
+ {0x193, 0x194, HB_Letter_Uppercase},
+ {0x195, 0x195, HB_Letter_Lowercase},
+ {0x196, 0x198, HB_Letter_Uppercase},
+ {0x199, 0x19b, HB_Letter_Lowercase},
+ {0x19c, 0x19d, HB_Letter_Uppercase},
+ {0x19e, 0x19e, HB_Letter_Lowercase},
+ {0x19f, 0x1a0, HB_Letter_Uppercase},
+ {0x1a1, 0x1a1, HB_Letter_Lowercase},
+ {0x1a2, 0x1a2, HB_Letter_Uppercase},
+ {0x1a3, 0x1a3, HB_Letter_Lowercase},
+ {0x1a4, 0x1a4, HB_Letter_Uppercase},
+ {0x1a5, 0x1a5, HB_Letter_Lowercase},
+ {0x1a6, 0x1a7, HB_Letter_Uppercase},
+ {0x1a8, 0x1a8, HB_Letter_Lowercase},
+ {0x1a9, 0x1a9, HB_Letter_Uppercase},
+ {0x1aa, 0x1ab, HB_Letter_Lowercase},
+ {0x1ac, 0x1ac, HB_Letter_Uppercase},
+ {0x1ad, 0x1ad, HB_Letter_Lowercase},
+ {0x1ae, 0x1af, HB_Letter_Uppercase},
+ {0x1b0, 0x1b0, HB_Letter_Lowercase},
+ {0x1b1, 0x1b3, HB_Letter_Uppercase},
+ {0x1b4, 0x1b4, HB_Letter_Lowercase},
+ {0x1b5, 0x1b5, HB_Letter_Uppercase},
+ {0x1b6, 0x1b6, HB_Letter_Lowercase},
+ {0x1b7, 0x1b8, HB_Letter_Uppercase},
+ {0x1b9, 0x1ba, HB_Letter_Lowercase},
+ {0x1bb, 0x1bb, HB_Letter_Other},
+ {0x1bc, 0x1bc, HB_Letter_Uppercase},
+ {0x1bd, 0x1bf, HB_Letter_Lowercase},
+ {0x1c0, 0x1c3, HB_Letter_Other},
+ {0x1c4, 0x1c4, HB_Letter_Uppercase},
+ {0x1c5, 0x1c5, HB_Letter_Titlecase},
+ {0x1c6, 0x1c6, HB_Letter_Lowercase},
+ {0x1c7, 0x1c7, HB_Letter_Uppercase},
+ {0x1c8, 0x1c8, HB_Letter_Titlecase},
+ {0x1c9, 0x1c9, HB_Letter_Lowercase},
+ {0x1ca, 0x1ca, HB_Letter_Uppercase},
+ {0x1cb, 0x1cb, HB_Letter_Titlecase},
+ {0x1cc, 0x1cc, HB_Letter_Lowercase},
+ {0x1cd, 0x1cd, HB_Letter_Uppercase},
+ {0x1ce, 0x1ce, HB_Letter_Lowercase},
+ {0x1cf, 0x1cf, HB_Letter_Uppercase},
+ {0x1d0, 0x1d0, HB_Letter_Lowercase},
+ {0x1d1, 0x1d1, HB_Letter_Uppercase},
+ {0x1d2, 0x1d2, HB_Letter_Lowercase},
+ {0x1d3, 0x1d3, HB_Letter_Uppercase},
+ {0x1d4, 0x1d4, HB_Letter_Lowercase},
+ {0x1d5, 0x1d5, HB_Letter_Uppercase},
+ {0x1d6, 0x1d6, HB_Letter_Lowercase},
+ {0x1d7, 0x1d7, HB_Letter_Uppercase},
+ {0x1d8, 0x1d8, HB_Letter_Lowercase},
+ {0x1d9, 0x1d9, HB_Letter_Uppercase},
+ {0x1da, 0x1da, HB_Letter_Lowercase},
+ {0x1db, 0x1db, HB_Letter_Uppercase},
+ {0x1dc, 0x1dd, HB_Letter_Lowercase},
+ {0x1de, 0x1de, HB_Letter_Uppercase},
+ {0x1df, 0x1df, HB_Letter_Lowercase},
+ {0x1e0, 0x1e0, HB_Letter_Uppercase},
+ {0x1e1, 0x1e1, HB_Letter_Lowercase},
+ {0x1e2, 0x1e2, HB_Letter_Uppercase},
+ {0x1e3, 0x1e3, HB_Letter_Lowercase},
+ {0x1e4, 0x1e4, HB_Letter_Uppercase},
+ {0x1e5, 0x1e5, HB_Letter_Lowercase},
+ {0x1e6, 0x1e6, HB_Letter_Uppercase},
+ {0x1e7, 0x1e7, HB_Letter_Lowercase},
+ {0x1e8, 0x1e8, HB_Letter_Uppercase},
+ {0x1e9, 0x1e9, HB_Letter_Lowercase},
+ {0x1ea, 0x1ea, HB_Letter_Uppercase},
+ {0x1eb, 0x1eb, HB_Letter_Lowercase},
+ {0x1ec, 0x1ec, HB_Letter_Uppercase},
+ {0x1ed, 0x1ed, HB_Letter_Lowercase},
+ {0x1ee, 0x1ee, HB_Letter_Uppercase},
+ {0x1ef, 0x1f0, HB_Letter_Lowercase},
+ {0x1f1, 0x1f1, HB_Letter_Uppercase},
+ {0x1f2, 0x1f2, HB_Letter_Titlecase},
+ {0x1f3, 0x1f3, HB_Letter_Lowercase},
+ {0x1f4, 0x1f4, HB_Letter_Uppercase},
+ {0x1f5, 0x1f5, HB_Letter_Lowercase},
+ {0x1f6, 0x1f8, HB_Letter_Uppercase},
+ {0x1f9, 0x1f9, HB_Letter_Lowercase},
+ {0x1fa, 0x1fa, HB_Letter_Uppercase},
+ {0x1fb, 0x1fb, HB_Letter_Lowercase},
+ {0x1fc, 0x1fc, HB_Letter_Uppercase},
+ {0x1fd, 0x1fd, HB_Letter_Lowercase},
+ {0x1fe, 0x1fe, HB_Letter_Uppercase},
+ {0x1ff, 0x1ff, HB_Letter_Lowercase},
+ {0x200, 0x200, HB_Letter_Uppercase},
+ {0x201, 0x201, HB_Letter_Lowercase},
+ {0x202, 0x202, HB_Letter_Uppercase},
+ {0x203, 0x203, HB_Letter_Lowercase},
+ {0x204, 0x204, HB_Letter_Uppercase},
+ {0x205, 0x205, HB_Letter_Lowercase},
+ {0x206, 0x206, HB_Letter_Uppercase},
+ {0x207, 0x207, HB_Letter_Lowercase},
+ {0x208, 0x208, HB_Letter_Uppercase},
+ {0x209, 0x209, HB_Letter_Lowercase},
+ {0x20a, 0x20a, HB_Letter_Uppercase},
+ {0x20b, 0x20b, HB_Letter_Lowercase},
+ {0x20c, 0x20c, HB_Letter_Uppercase},
+ {0x20d, 0x20d, HB_Letter_Lowercase},
+ {0x20e, 0x20e, HB_Letter_Uppercase},
+ {0x20f, 0x20f, HB_Letter_Lowercase},
+ {0x210, 0x210, HB_Letter_Uppercase},
+ {0x211, 0x211, HB_Letter_Lowercase},
+ {0x212, 0x212, HB_Letter_Uppercase},
+ {0x213, 0x213, HB_Letter_Lowercase},
+ {0x214, 0x214, HB_Letter_Uppercase},
+ {0x215, 0x215, HB_Letter_Lowercase},
+ {0x216, 0x216, HB_Letter_Uppercase},
+ {0x217, 0x217, HB_Letter_Lowercase},
+ {0x218, 0x218, HB_Letter_Uppercase},
+ {0x219, 0x219, HB_Letter_Lowercase},
+ {0x21a, 0x21a, HB_Letter_Uppercase},
+ {0x21b, 0x21b, HB_Letter_Lowercase},
+ {0x21c, 0x21c, HB_Letter_Uppercase},
+ {0x21d, 0x21d, HB_Letter_Lowercase},
+ {0x21e, 0x21e, HB_Letter_Uppercase},
+ {0x21f, 0x21f, HB_Letter_Lowercase},
+ {0x220, 0x220, HB_Letter_Uppercase},
+ {0x221, 0x221, HB_Letter_Lowercase},
+ {0x222, 0x222, HB_Letter_Uppercase},
+ {0x223, 0x223, HB_Letter_Lowercase},
+ {0x224, 0x224, HB_Letter_Uppercase},
+ {0x225, 0x225, HB_Letter_Lowercase},
+ {0x226, 0x226, HB_Letter_Uppercase},
+ {0x227, 0x227, HB_Letter_Lowercase},
+ {0x228, 0x228, HB_Letter_Uppercase},
+ {0x229, 0x229, HB_Letter_Lowercase},
+ {0x22a, 0x22a, HB_Letter_Uppercase},
+ {0x22b, 0x22b, HB_Letter_Lowercase},
+ {0x22c, 0x22c, HB_Letter_Uppercase},
+ {0x22d, 0x22d, HB_Letter_Lowercase},
+ {0x22e, 0x22e, HB_Letter_Uppercase},
+ {0x22f, 0x22f, HB_Letter_Lowercase},
+ {0x230, 0x230, HB_Letter_Uppercase},
+ {0x231, 0x231, HB_Letter_Lowercase},
+ {0x232, 0x232, HB_Letter_Uppercase},
+ {0x233, 0x239, HB_Letter_Lowercase},
+ {0x23a, 0x23b, HB_Letter_Uppercase},
+ {0x23c, 0x23c, HB_Letter_Lowercase},
+ {0x23d, 0x23e, HB_Letter_Uppercase},
+ {0x23f, 0x240, HB_Letter_Lowercase},
+ {0x241, 0x241, HB_Letter_Uppercase},
+ {0x242, 0x242, HB_Letter_Lowercase},
+ {0x243, 0x246, HB_Letter_Uppercase},
+ {0x247, 0x247, HB_Letter_Lowercase},
+ {0x248, 0x248, HB_Letter_Uppercase},
+ {0x249, 0x249, HB_Letter_Lowercase},
+ {0x24a, 0x24a, HB_Letter_Uppercase},
+ {0x24b, 0x24b, HB_Letter_Lowercase},
+ {0x24c, 0x24c, HB_Letter_Uppercase},
+ {0x24d, 0x24d, HB_Letter_Lowercase},
+ {0x24e, 0x24e, HB_Letter_Uppercase},
+ {0x24f, 0x293, HB_Letter_Lowercase},
+ {0x294, 0x294, HB_Letter_Other},
+ {0x295, 0x2af, HB_Letter_Lowercase},
+ {0x2b0, 0x2c1, HB_Letter_Modifier},
+ {0x2c2, 0x2c5, HB_Symbol_Modifier},
+ {0x2c6, 0x2d1, HB_Letter_Modifier},
+ {0x2d2, 0x2df, HB_Symbol_Modifier},
+ {0x2e0, 0x2e4, HB_Letter_Modifier},
+ {0x2e5, 0x2eb, HB_Symbol_Modifier},
+ {0x2ec, 0x2ec, HB_Letter_Modifier},
+ {0x2ed, 0x2ed, HB_Symbol_Modifier},
+ {0x2ee, 0x2ee, HB_Letter_Modifier},
+ {0x2ef, 0x2ff, HB_Symbol_Modifier},
+ {0x300, 0x36f, HB_Mark_NonSpacing},
+ {0x370, 0x370, HB_Letter_Uppercase},
+ {0x371, 0x371, HB_Letter_Lowercase},
+ {0x372, 0x372, HB_Letter_Uppercase},
+ {0x373, 0x373, HB_Letter_Lowercase},
+ {0x374, 0x374, HB_Letter_Modifier},
+ {0x375, 0x375, HB_Symbol_Modifier},
+ {0x376, 0x376, HB_Letter_Uppercase},
+ {0x377, 0x377, HB_Letter_Lowercase},
+ {0x378, 0x379, HB_Other_NotAssigned},
+ {0x37a, 0x37a, HB_Letter_Modifier},
+ {0x37b, 0x37d, HB_Letter_Lowercase},
+ {0x37e, 0x37e, HB_Punctuation_Other},
+ {0x37f, 0x383, HB_Other_NotAssigned},
+ {0x384, 0x385, HB_Symbol_Modifier},
+ {0x386, 0x386, HB_Letter_Uppercase},
+ {0x387, 0x387, HB_Punctuation_Other},
+ {0x388, 0x38a, HB_Letter_Uppercase},
+ {0x38b, 0x38b, HB_Other_NotAssigned},
+ {0x38c, 0x38c, HB_Letter_Uppercase},
+ {0x38d, 0x38d, HB_Other_NotAssigned},
+ {0x38e, 0x38f, HB_Letter_Uppercase},
+ {0x390, 0x390, HB_Letter_Lowercase},
+ {0x391, 0x3a1, HB_Letter_Uppercase},
+ {0x3a2, 0x3a2, HB_Other_NotAssigned},
+ {0x3a3, 0x3ab, HB_Letter_Uppercase},
+ {0x3ac, 0x3ce, HB_Letter_Lowercase},
+ {0x3cf, 0x3cf, HB_Letter_Uppercase},
+ {0x3d0, 0x3d1, HB_Letter_Lowercase},
+ {0x3d2, 0x3d4, HB_Letter_Uppercase},
+ {0x3d5, 0x3d7, HB_Letter_Lowercase},
+ {0x3d8, 0x3d8, HB_Letter_Uppercase},
+ {0x3d9, 0x3d9, HB_Letter_Lowercase},
+ {0x3da, 0x3da, HB_Letter_Uppercase},
+ {0x3db, 0x3db, HB_Letter_Lowercase},
+ {0x3dc, 0x3dc, HB_Letter_Uppercase},
+ {0x3dd, 0x3dd, HB_Letter_Lowercase},
+ {0x3de, 0x3de, HB_Letter_Uppercase},
+ {0x3df, 0x3df, HB_Letter_Lowercase},
+ {0x3e0, 0x3e0, HB_Letter_Uppercase},
+ {0x3e1, 0x3e1, HB_Letter_Lowercase},
+ {0x3e2, 0x3e2, HB_Letter_Uppercase},
+ {0x3e3, 0x3e3, HB_Letter_Lowercase},
+ {0x3e4, 0x3e4, HB_Letter_Uppercase},
+ {0x3e5, 0x3e5, HB_Letter_Lowercase},
+ {0x3e6, 0x3e6, HB_Letter_Uppercase},
+ {0x3e7, 0x3e7, HB_Letter_Lowercase},
+ {0x3e8, 0x3e8, HB_Letter_Uppercase},
+ {0x3e9, 0x3e9, HB_Letter_Lowercase},
+ {0x3ea, 0x3ea, HB_Letter_Uppercase},
+ {0x3eb, 0x3eb, HB_Letter_Lowercase},
+ {0x3ec, 0x3ec, HB_Letter_Uppercase},
+ {0x3ed, 0x3ed, HB_Letter_Lowercase},
+ {0x3ee, 0x3ee, HB_Letter_Uppercase},
+ {0x3ef, 0x3f3, HB_Letter_Lowercase},
+ {0x3f4, 0x3f4, HB_Letter_Uppercase},
+ {0x3f5, 0x3f5, HB_Letter_Lowercase},
+ {0x3f6, 0x3f6, HB_Symbol_Math},
+ {0x3f7, 0x3f7, HB_Letter_Uppercase},
+ {0x3f8, 0x3f8, HB_Letter_Lowercase},
+ {0x3f9, 0x3fa, HB_Letter_Uppercase},
+ {0x3fb, 0x3fc, HB_Letter_Lowercase},
+ {0x3fd, 0x42f, HB_Letter_Uppercase},
+ {0x430, 0x45f, HB_Letter_Lowercase},
+ {0x460, 0x460, HB_Letter_Uppercase},
+ {0x461, 0x461, HB_Letter_Lowercase},
+ {0x462, 0x462, HB_Letter_Uppercase},
+ {0x463, 0x463, HB_Letter_Lowercase},
+ {0x464, 0x464, HB_Letter_Uppercase},
+ {0x465, 0x465, HB_Letter_Lowercase},
+ {0x466, 0x466, HB_Letter_Uppercase},
+ {0x467, 0x467, HB_Letter_Lowercase},
+ {0x468, 0x468, HB_Letter_Uppercase},
+ {0x469, 0x469, HB_Letter_Lowercase},
+ {0x46a, 0x46a, HB_Letter_Uppercase},
+ {0x46b, 0x46b, HB_Letter_Lowercase},
+ {0x46c, 0x46c, HB_Letter_Uppercase},
+ {0x46d, 0x46d, HB_Letter_Lowercase},
+ {0x46e, 0x46e, HB_Letter_Uppercase},
+ {0x46f, 0x46f, HB_Letter_Lowercase},
+ {0x470, 0x470, HB_Letter_Uppercase},
+ {0x471, 0x471, HB_Letter_Lowercase},
+ {0x472, 0x472, HB_Letter_Uppercase},
+ {0x473, 0x473, HB_Letter_Lowercase},
+ {0x474, 0x474, HB_Letter_Uppercase},
+ {0x475, 0x475, HB_Letter_Lowercase},
+ {0x476, 0x476, HB_Letter_Uppercase},
+ {0x477, 0x477, HB_Letter_Lowercase},
+ {0x478, 0x478, HB_Letter_Uppercase},
+ {0x479, 0x479, HB_Letter_Lowercase},
+ {0x47a, 0x47a, HB_Letter_Uppercase},
+ {0x47b, 0x47b, HB_Letter_Lowercase},
+ {0x47c, 0x47c, HB_Letter_Uppercase},
+ {0x47d, 0x47d, HB_Letter_Lowercase},
+ {0x47e, 0x47e, HB_Letter_Uppercase},
+ {0x47f, 0x47f, HB_Letter_Lowercase},
+ {0x480, 0x480, HB_Letter_Uppercase},
+ {0x481, 0x481, HB_Letter_Lowercase},
+ {0x482, 0x482, HB_Symbol_Other},
+ {0x483, 0x487, HB_Mark_NonSpacing},
+ {0x488, 0x489, HB_Mark_Enclosing},
+ {0x48a, 0x48a, HB_Letter_Uppercase},
+ {0x48b, 0x48b, HB_Letter_Lowercase},
+ {0x48c, 0x48c, HB_Letter_Uppercase},
+ {0x48d, 0x48d, HB_Letter_Lowercase},
+ {0x48e, 0x48e, HB_Letter_Uppercase},
+ {0x48f, 0x48f, HB_Letter_Lowercase},
+ {0x490, 0x490, HB_Letter_Uppercase},
+ {0x491, 0x491, HB_Letter_Lowercase},
+ {0x492, 0x492, HB_Letter_Uppercase},
+ {0x493, 0x493, HB_Letter_Lowercase},
+ {0x494, 0x494, HB_Letter_Uppercase},
+ {0x495, 0x495, HB_Letter_Lowercase},
+ {0x496, 0x496, HB_Letter_Uppercase},
+ {0x497, 0x497, HB_Letter_Lowercase},
+ {0x498, 0x498, HB_Letter_Uppercase},
+ {0x499, 0x499, HB_Letter_Lowercase},
+ {0x49a, 0x49a, HB_Letter_Uppercase},
+ {0x49b, 0x49b, HB_Letter_Lowercase},
+ {0x49c, 0x49c, HB_Letter_Uppercase},
+ {0x49d, 0x49d, HB_Letter_Lowercase},
+ {0x49e, 0x49e, HB_Letter_Uppercase},
+ {0x49f, 0x49f, HB_Letter_Lowercase},
+ {0x4a0, 0x4a0, HB_Letter_Uppercase},
+ {0x4a1, 0x4a1, HB_Letter_Lowercase},
+ {0x4a2, 0x4a2, HB_Letter_Uppercase},
+ {0x4a3, 0x4a3, HB_Letter_Lowercase},
+ {0x4a4, 0x4a4, HB_Letter_Uppercase},
+ {0x4a5, 0x4a5, HB_Letter_Lowercase},
+ {0x4a6, 0x4a6, HB_Letter_Uppercase},
+ {0x4a7, 0x4a7, HB_Letter_Lowercase},
+ {0x4a8, 0x4a8, HB_Letter_Uppercase},
+ {0x4a9, 0x4a9, HB_Letter_Lowercase},
+ {0x4aa, 0x4aa, HB_Letter_Uppercase},
+ {0x4ab, 0x4ab, HB_Letter_Lowercase},
+ {0x4ac, 0x4ac, HB_Letter_Uppercase},
+ {0x4ad, 0x4ad, HB_Letter_Lowercase},
+ {0x4ae, 0x4ae, HB_Letter_Uppercase},
+ {0x4af, 0x4af, HB_Letter_Lowercase},
+ {0x4b0, 0x4b0, HB_Letter_Uppercase},
+ {0x4b1, 0x4b1, HB_Letter_Lowercase},
+ {0x4b2, 0x4b2, HB_Letter_Uppercase},
+ {0x4b3, 0x4b3, HB_Letter_Lowercase},
+ {0x4b4, 0x4b4, HB_Letter_Uppercase},
+ {0x4b5, 0x4b5, HB_Letter_Lowercase},
+ {0x4b6, 0x4b6, HB_Letter_Uppercase},
+ {0x4b7, 0x4b7, HB_Letter_Lowercase},
+ {0x4b8, 0x4b8, HB_Letter_Uppercase},
+ {0x4b9, 0x4b9, HB_Letter_Lowercase},
+ {0x4ba, 0x4ba, HB_Letter_Uppercase},
+ {0x4bb, 0x4bb, HB_Letter_Lowercase},
+ {0x4bc, 0x4bc, HB_Letter_Uppercase},
+ {0x4bd, 0x4bd, HB_Letter_Lowercase},
+ {0x4be, 0x4be, HB_Letter_Uppercase},
+ {0x4bf, 0x4bf, HB_Letter_Lowercase},
+ {0x4c0, 0x4c1, HB_Letter_Uppercase},
+ {0x4c2, 0x4c2, HB_Letter_Lowercase},
+ {0x4c3, 0x4c3, HB_Letter_Uppercase},
+ {0x4c4, 0x4c4, HB_Letter_Lowercase},
+ {0x4c5, 0x4c5, HB_Letter_Uppercase},
+ {0x4c6, 0x4c6, HB_Letter_Lowercase},
+ {0x4c7, 0x4c7, HB_Letter_Uppercase},
+ {0x4c8, 0x4c8, HB_Letter_Lowercase},
+ {0x4c9, 0x4c9, HB_Letter_Uppercase},
+ {0x4ca, 0x4ca, HB_Letter_Lowercase},
+ {0x4cb, 0x4cb, HB_Letter_Uppercase},
+ {0x4cc, 0x4cc, HB_Letter_Lowercase},
+ {0x4cd, 0x4cd, HB_Letter_Uppercase},
+ {0x4ce, 0x4cf, HB_Letter_Lowercase},
+ {0x4d0, 0x4d0, HB_Letter_Uppercase},
+ {0x4d1, 0x4d1, HB_Letter_Lowercase},
+ {0x4d2, 0x4d2, HB_Letter_Uppercase},
+ {0x4d3, 0x4d3, HB_Letter_Lowercase},
+ {0x4d4, 0x4d4, HB_Letter_Uppercase},
+ {0x4d5, 0x4d5, HB_Letter_Lowercase},
+ {0x4d6, 0x4d6, HB_Letter_Uppercase},
+ {0x4d7, 0x4d7, HB_Letter_Lowercase},
+ {0x4d8, 0x4d8, HB_Letter_Uppercase},
+ {0x4d9, 0x4d9, HB_Letter_Lowercase},
+ {0x4da, 0x4da, HB_Letter_Uppercase},
+ {0x4db, 0x4db, HB_Letter_Lowercase},
+ {0x4dc, 0x4dc, HB_Letter_Uppercase},
+ {0x4dd, 0x4dd, HB_Letter_Lowercase},
+ {0x4de, 0x4de, HB_Letter_Uppercase},
+ {0x4df, 0x4df, HB_Letter_Lowercase},
+ {0x4e0, 0x4e0, HB_Letter_Uppercase},
+ {0x4e1, 0x4e1, HB_Letter_Lowercase},
+ {0x4e2, 0x4e2, HB_Letter_Uppercase},
+ {0x4e3, 0x4e3, HB_Letter_Lowercase},
+ {0x4e4, 0x4e4, HB_Letter_Uppercase},
+ {0x4e5, 0x4e5, HB_Letter_Lowercase},
+ {0x4e6, 0x4e6, HB_Letter_Uppercase},
+ {0x4e7, 0x4e7, HB_Letter_Lowercase},
+ {0x4e8, 0x4e8, HB_Letter_Uppercase},
+ {0x4e9, 0x4e9, HB_Letter_Lowercase},
+ {0x4ea, 0x4ea, HB_Letter_Uppercase},
+ {0x4eb, 0x4eb, HB_Letter_Lowercase},
+ {0x4ec, 0x4ec, HB_Letter_Uppercase},
+ {0x4ed, 0x4ed, HB_Letter_Lowercase},
+ {0x4ee, 0x4ee, HB_Letter_Uppercase},
+ {0x4ef, 0x4ef, HB_Letter_Lowercase},
+ {0x4f0, 0x4f0, HB_Letter_Uppercase},
+ {0x4f1, 0x4f1, HB_Letter_Lowercase},
+ {0x4f2, 0x4f2, HB_Letter_Uppercase},
+ {0x4f3, 0x4f3, HB_Letter_Lowercase},
+ {0x4f4, 0x4f4, HB_Letter_Uppercase},
+ {0x4f5, 0x4f5, HB_Letter_Lowercase},
+ {0x4f6, 0x4f6, HB_Letter_Uppercase},
+ {0x4f7, 0x4f7, HB_Letter_Lowercase},
+ {0x4f8, 0x4f8, HB_Letter_Uppercase},
+ {0x4f9, 0x4f9, HB_Letter_Lowercase},
+ {0x4fa, 0x4fa, HB_Letter_Uppercase},
+ {0x4fb, 0x4fb, HB_Letter_Lowercase},
+ {0x4fc, 0x4fc, HB_Letter_Uppercase},
+ {0x4fd, 0x4fd, HB_Letter_Lowercase},
+ {0x4fe, 0x4fe, HB_Letter_Uppercase},
+ {0x4ff, 0x4ff, HB_Letter_Lowercase},
+ {0x500, 0x500, HB_Letter_Uppercase},
+ {0x501, 0x501, HB_Letter_Lowercase},
+ {0x502, 0x502, HB_Letter_Uppercase},
+ {0x503, 0x503, HB_Letter_Lowercase},
+ {0x504, 0x504, HB_Letter_Uppercase},
+ {0x505, 0x505, HB_Letter_Lowercase},
+ {0x506, 0x506, HB_Letter_Uppercase},
+ {0x507, 0x507, HB_Letter_Lowercase},
+ {0x508, 0x508, HB_Letter_Uppercase},
+ {0x509, 0x509, HB_Letter_Lowercase},
+ {0x50a, 0x50a, HB_Letter_Uppercase},
+ {0x50b, 0x50b, HB_Letter_Lowercase},
+ {0x50c, 0x50c, HB_Letter_Uppercase},
+ {0x50d, 0x50d, HB_Letter_Lowercase},
+ {0x50e, 0x50e, HB_Letter_Uppercase},
+ {0x50f, 0x50f, HB_Letter_Lowercase},
+ {0x510, 0x510, HB_Letter_Uppercase},
+ {0x511, 0x511, HB_Letter_Lowercase},
+ {0x512, 0x512, HB_Letter_Uppercase},
+ {0x513, 0x513, HB_Letter_Lowercase},
+ {0x514, 0x514, HB_Letter_Uppercase},
+ {0x515, 0x515, HB_Letter_Lowercase},
+ {0x516, 0x516, HB_Letter_Uppercase},
+ {0x517, 0x517, HB_Letter_Lowercase},
+ {0x518, 0x518, HB_Letter_Uppercase},
+ {0x519, 0x519, HB_Letter_Lowercase},
+ {0x51a, 0x51a, HB_Letter_Uppercase},
+ {0x51b, 0x51b, HB_Letter_Lowercase},
+ {0x51c, 0x51c, HB_Letter_Uppercase},
+ {0x51d, 0x51d, HB_Letter_Lowercase},
+ {0x51e, 0x51e, HB_Letter_Uppercase},
+ {0x51f, 0x51f, HB_Letter_Lowercase},
+ {0x520, 0x520, HB_Letter_Uppercase},
+ {0x521, 0x521, HB_Letter_Lowercase},
+ {0x522, 0x522, HB_Letter_Uppercase},
+ {0x523, 0x523, HB_Letter_Lowercase},
+ {0x524, 0x530, HB_Other_NotAssigned},
+ {0x531, 0x556, HB_Letter_Uppercase},
+ {0x557, 0x558, HB_Other_NotAssigned},
+ {0x559, 0x559, HB_Letter_Modifier},
+ {0x55a, 0x55f, HB_Punctuation_Other},
+ {0x560, 0x560, HB_Other_NotAssigned},
+ {0x561, 0x587, HB_Letter_Lowercase},
+ {0x588, 0x588, HB_Other_NotAssigned},
+ {0x589, 0x589, HB_Punctuation_Other},
+ {0x58a, 0x58a, HB_Punctuation_Dash},
+ {0x58b, 0x590, HB_Other_NotAssigned},
+ {0x591, 0x5bd, HB_Mark_NonSpacing},
+ {0x5be, 0x5be, HB_Punctuation_Dash},
+ {0x5bf, 0x5bf, HB_Mark_NonSpacing},
+ {0x5c0, 0x5c0, HB_Punctuation_Other},
+ {0x5c1, 0x5c2, HB_Mark_NonSpacing},
+ {0x5c3, 0x5c3, HB_Punctuation_Other},
+ {0x5c4, 0x5c5, HB_Mark_NonSpacing},
+ {0x5c6, 0x5c6, HB_Punctuation_Other},
+ {0x5c7, 0x5c7, HB_Mark_NonSpacing},
+ {0x5c8, 0x5cf, HB_Other_NotAssigned},
+ {0x5d0, 0x5ea, HB_Letter_Other},
+ {0x5eb, 0x5ef, HB_Other_NotAssigned},
+ {0x5f0, 0x5f2, HB_Letter_Other},
+ {0x5f3, 0x5f4, HB_Punctuation_Other},
+ {0x5f5, 0x5ff, HB_Other_NotAssigned},
+ {0x600, 0x603, HB_Other_Format},
+ {0x604, 0x605, HB_Other_NotAssigned},
+ {0x606, 0x608, HB_Symbol_Math},
+ {0x609, 0x60a, HB_Punctuation_Other},
+ {0x60b, 0x60b, HB_Symbol_Currency},
+ {0x60c, 0x60d, HB_Punctuation_Other},
+ {0x60e, 0x60f, HB_Symbol_Other},
+ {0x610, 0x61a, HB_Mark_NonSpacing},
+ {0x61b, 0x61b, HB_Punctuation_Other},
+ {0x61c, 0x61d, HB_Other_NotAssigned},
+ {0x61e, 0x61f, HB_Punctuation_Other},
+ {0x620, 0x620, HB_Other_NotAssigned},
+ {0x621, 0x63f, HB_Letter_Other},
+ {0x640, 0x640, HB_Letter_Modifier},
+ {0x641, 0x64a, HB_Letter_Other},
+ {0x64b, 0x65e, HB_Mark_NonSpacing},
+ {0x65f, 0x65f, HB_Other_NotAssigned},
+ {0x660, 0x669, HB_Number_DecimalDigit},
+ {0x66a, 0x66d, HB_Punctuation_Other},
+ {0x66e, 0x66f, HB_Letter_Other},
+ {0x670, 0x670, HB_Mark_NonSpacing},
+ {0x671, 0x6d3, HB_Letter_Other},
+ {0x6d4, 0x6d4, HB_Punctuation_Other},
+ {0x6d5, 0x6d5, HB_Letter_Other},
+ {0x6d6, 0x6dc, HB_Mark_NonSpacing},
+ {0x6dd, 0x6dd, HB_Other_Format},
+ {0x6de, 0x6de, HB_Mark_Enclosing},
+ {0x6df, 0x6e4, HB_Mark_NonSpacing},
+ {0x6e5, 0x6e6, HB_Letter_Modifier},
+ {0x6e7, 0x6e8, HB_Mark_NonSpacing},
+ {0x6e9, 0x6e9, HB_Symbol_Other},
+ {0x6ea, 0x6ed, HB_Mark_NonSpacing},
+ {0x6ee, 0x6ef, HB_Letter_Other},
+ {0x6f0, 0x6f9, HB_Number_DecimalDigit},
+ {0x6fa, 0x6fc, HB_Letter_Other},
+ {0x6fd, 0x6fe, HB_Symbol_Other},
+ {0x6ff, 0x6ff, HB_Letter_Other},
+ {0x700, 0x70d, HB_Punctuation_Other},
+ {0x70e, 0x70e, HB_Other_NotAssigned},
+ {0x70f, 0x70f, HB_Other_Format},
+ {0x710, 0x710, HB_Letter_Other},
+ {0x711, 0x711, HB_Mark_NonSpacing},
+ {0x712, 0x72f, HB_Letter_Other},
+ {0x730, 0x74a, HB_Mark_NonSpacing},
+ {0x74b, 0x74c, HB_Other_NotAssigned},
+ {0x74d, 0x7a5, HB_Letter_Other},
+ {0x7a6, 0x7b0, HB_Mark_NonSpacing},
+ {0x7b1, 0x7b1, HB_Letter_Other},
+ {0x7b2, 0x7bf, HB_Other_NotAssigned},
+ {0x7c0, 0x7c9, HB_Number_DecimalDigit},
+ {0x7ca, 0x7ea, HB_Letter_Other},
+ {0x7eb, 0x7f3, HB_Mark_NonSpacing},
+ {0x7f4, 0x7f5, HB_Letter_Modifier},
+ {0x7f6, 0x7f6, HB_Symbol_Other},
+ {0x7f7, 0x7f9, HB_Punctuation_Other},
+ {0x7fa, 0x7fa, HB_Letter_Modifier},
+ {0x7fb, 0x900, HB_Other_NotAssigned},
+ {0x901, 0x902, HB_Mark_NonSpacing},
+ {0x903, 0x903, HB_Mark_SpacingCombining},
+ {0x904, 0x939, HB_Letter_Other},
+ {0x93a, 0x93b, HB_Other_NotAssigned},
+ {0x93c, 0x93c, HB_Mark_NonSpacing},
+ {0x93d, 0x93d, HB_Letter_Other},
+ {0x93e, 0x940, HB_Mark_SpacingCombining},
+ {0x941, 0x948, HB_Mark_NonSpacing},
+ {0x949, 0x94c, HB_Mark_SpacingCombining},
+ {0x94d, 0x94d, HB_Mark_NonSpacing},
+ {0x94e, 0x94f, HB_Other_NotAssigned},
+ {0x950, 0x950, HB_Letter_Other},
+ {0x951, 0x954, HB_Mark_NonSpacing},
+ {0x955, 0x957, HB_Other_NotAssigned},
+ {0x958, 0x961, HB_Letter_Other},
+ {0x962, 0x963, HB_Mark_NonSpacing},
+ {0x964, 0x965, HB_Punctuation_Other},
+ {0x966, 0x96f, HB_Number_DecimalDigit},
+ {0x970, 0x970, HB_Punctuation_Other},
+ {0x971, 0x971, HB_Letter_Modifier},
+ {0x972, 0x972, HB_Letter_Other},
+ {0x973, 0x97a, HB_Other_NotAssigned},
+ {0x97b, 0x97f, HB_Letter_Other},
+ {0x980, 0x980, HB_Other_NotAssigned},
+ {0x981, 0x981, HB_Mark_NonSpacing},
+ {0x982, 0x983, HB_Mark_SpacingCombining},
+ {0x984, 0x984, HB_Other_NotAssigned},
+ {0x985, 0x98c, HB_Letter_Other},
+ {0x98d, 0x98e, HB_Other_NotAssigned},
+ {0x98f, 0x990, HB_Letter_Other},
+ {0x991, 0x992, HB_Other_NotAssigned},
+ {0x993, 0x9a8, HB_Letter_Other},
+ {0x9a9, 0x9a9, HB_Other_NotAssigned},
+ {0x9aa, 0x9b0, HB_Letter_Other},
+ {0x9b1, 0x9b1, HB_Other_NotAssigned},
+ {0x9b2, 0x9b2, HB_Letter_Other},
+ {0x9b3, 0x9b5, HB_Other_NotAssigned},
+ {0x9b6, 0x9b9, HB_Letter_Other},
+ {0x9ba, 0x9bb, HB_Other_NotAssigned},
+ {0x9bc, 0x9bc, HB_Mark_NonSpacing},
+ {0x9bd, 0x9bd, HB_Letter_Other},
+ {0x9be, 0x9c0, HB_Mark_SpacingCombining},
+ {0x9c1, 0x9c4, HB_Mark_NonSpacing},
+ {0x9c5, 0x9c6, HB_Other_NotAssigned},
+ {0x9c7, 0x9c8, HB_Mark_SpacingCombining},
+ {0x9c9, 0x9ca, HB_Other_NotAssigned},
+ {0x9cb, 0x9cc, HB_Mark_SpacingCombining},
+ {0x9cd, 0x9cd, HB_Mark_NonSpacing},
+ {0x9ce, 0x9ce, HB_Letter_Other},
+ {0x9cf, 0x9d6, HB_Other_NotAssigned},
+ {0x9d7, 0x9d7, HB_Mark_SpacingCombining},
+ {0x9d8, 0x9db, HB_Other_NotAssigned},
+ {0x9dc, 0x9dd, HB_Letter_Other},
+ {0x9de, 0x9de, HB_Other_NotAssigned},
+ {0x9df, 0x9e1, HB_Letter_Other},
+ {0x9e2, 0x9e3, HB_Mark_NonSpacing},
+ {0x9e4, 0x9e5, HB_Other_NotAssigned},
+ {0x9e6, 0x9ef, HB_Number_DecimalDigit},
+ {0x9f0, 0x9f1, HB_Letter_Other},
+ {0x9f2, 0x9f3, HB_Symbol_Currency},
+ {0x9f4, 0x9f9, HB_Number_Other},
+ {0x9fa, 0x9fa, HB_Symbol_Other},
+ {0x9fb, 0xa00, HB_Other_NotAssigned},
+ {0xa01, 0xa02, HB_Mark_NonSpacing},
+ {0xa03, 0xa03, HB_Mark_SpacingCombining},
+ {0xa04, 0xa04, HB_Other_NotAssigned},
+ {0xa05, 0xa0a, HB_Letter_Other},
+ {0xa0b, 0xa0e, HB_Other_NotAssigned},
+ {0xa0f, 0xa10, HB_Letter_Other},
+ {0xa11, 0xa12, HB_Other_NotAssigned},
+ {0xa13, 0xa28, HB_Letter_Other},
+ {0xa29, 0xa29, HB_Other_NotAssigned},
+ {0xa2a, 0xa30, HB_Letter_Other},
+ {0xa31, 0xa31, HB_Other_NotAssigned},
+ {0xa32, 0xa33, HB_Letter_Other},
+ {0xa34, 0xa34, HB_Other_NotAssigned},
+ {0xa35, 0xa36, HB_Letter_Other},
+ {0xa37, 0xa37, HB_Other_NotAssigned},
+ {0xa38, 0xa39, HB_Letter_Other},
+ {0xa3a, 0xa3b, HB_Other_NotAssigned},
+ {0xa3c, 0xa3c, HB_Mark_NonSpacing},
+ {0xa3d, 0xa3d, HB_Other_NotAssigned},
+ {0xa3e, 0xa40, HB_Mark_SpacingCombining},
+ {0xa41, 0xa42, HB_Mark_NonSpacing},
+ {0xa43, 0xa46, HB_Other_NotAssigned},
+ {0xa47, 0xa48, HB_Mark_NonSpacing},
+ {0xa49, 0xa4a, HB_Other_NotAssigned},
+ {0xa4b, 0xa4d, HB_Mark_NonSpacing},
+ {0xa4e, 0xa50, HB_Other_NotAssigned},
+ {0xa51, 0xa51, HB_Mark_NonSpacing},
+ {0xa52, 0xa58, HB_Other_NotAssigned},
+ {0xa59, 0xa5c, HB_Letter_Other},
+ {0xa5d, 0xa5d, HB_Other_NotAssigned},
+ {0xa5e, 0xa5e, HB_Letter_Other},
+ {0xa5f, 0xa65, HB_Other_NotAssigned},
+ {0xa66, 0xa6f, HB_Number_DecimalDigit},
+ {0xa70, 0xa71, HB_Mark_NonSpacing},
+ {0xa72, 0xa74, HB_Letter_Other},
+ {0xa75, 0xa75, HB_Mark_NonSpacing},
+ {0xa76, 0xa80, HB_Other_NotAssigned},
+ {0xa81, 0xa82, HB_Mark_NonSpacing},
+ {0xa83, 0xa83, HB_Mark_SpacingCombining},
+ {0xa84, 0xa84, HB_Other_NotAssigned},
+ {0xa85, 0xa8d, HB_Letter_Other},
+ {0xa8e, 0xa8e, HB_Other_NotAssigned},
+ {0xa8f, 0xa91, HB_Letter_Other},
+ {0xa92, 0xa92, HB_Other_NotAssigned},
+ {0xa93, 0xaa8, HB_Letter_Other},
+ {0xaa9, 0xaa9, HB_Other_NotAssigned},
+ {0xaaa, 0xab0, HB_Letter_Other},
+ {0xab1, 0xab1, HB_Other_NotAssigned},
+ {0xab2, 0xab3, HB_Letter_Other},
+ {0xab4, 0xab4, HB_Other_NotAssigned},
+ {0xab5, 0xab9, HB_Letter_Other},
+ {0xaba, 0xabb, HB_Other_NotAssigned},
+ {0xabc, 0xabc, HB_Mark_NonSpacing},
+ {0xabd, 0xabd, HB_Letter_Other},
+ {0xabe, 0xac0, HB_Mark_SpacingCombining},
+ {0xac1, 0xac5, HB_Mark_NonSpacing},
+ {0xac6, 0xac6, HB_Other_NotAssigned},
+ {0xac7, 0xac8, HB_Mark_NonSpacing},
+ {0xac9, 0xac9, HB_Mark_SpacingCombining},
+ {0xaca, 0xaca, HB_Other_NotAssigned},
+ {0xacb, 0xacc, HB_Mark_SpacingCombining},
+ {0xacd, 0xacd, HB_Mark_NonSpacing},
+ {0xace, 0xacf, HB_Other_NotAssigned},
+ {0xad0, 0xad0, HB_Letter_Other},
+ {0xad1, 0xadf, HB_Other_NotAssigned},
+ {0xae0, 0xae1, HB_Letter_Other},
+ {0xae2, 0xae3, HB_Mark_NonSpacing},
+ {0xae4, 0xae5, HB_Other_NotAssigned},
+ {0xae6, 0xaef, HB_Number_DecimalDigit},
+ {0xaf0, 0xaf0, HB_Other_NotAssigned},
+ {0xaf1, 0xaf1, HB_Symbol_Currency},
+ {0xaf2, 0xb00, HB_Other_NotAssigned},
+ {0xb01, 0xb01, HB_Mark_NonSpacing},
+ {0xb02, 0xb03, HB_Mark_SpacingCombining},
+ {0xb04, 0xb04, HB_Other_NotAssigned},
+ {0xb05, 0xb0c, HB_Letter_Other},
+ {0xb0d, 0xb0e, HB_Other_NotAssigned},
+ {0xb0f, 0xb10, HB_Letter_Other},
+ {0xb11, 0xb12, HB_Other_NotAssigned},
+ {0xb13, 0xb28, HB_Letter_Other},
+ {0xb29, 0xb29, HB_Other_NotAssigned},
+ {0xb2a, 0xb30, HB_Letter_Other},
+ {0xb31, 0xb31, HB_Other_NotAssigned},
+ {0xb32, 0xb33, HB_Letter_Other},
+ {0xb34, 0xb34, HB_Other_NotAssigned},
+ {0xb35, 0xb39, HB_Letter_Other},
+ {0xb3a, 0xb3b, HB_Other_NotAssigned},
+ {0xb3c, 0xb3c, HB_Mark_NonSpacing},
+ {0xb3d, 0xb3d, HB_Letter_Other},
+ {0xb3e, 0xb3e, HB_Mark_SpacingCombining},
+ {0xb3f, 0xb3f, HB_Mark_NonSpacing},
+ {0xb40, 0xb40, HB_Mark_SpacingCombining},
+ {0xb41, 0xb44, HB_Mark_NonSpacing},
+ {0xb45, 0xb46, HB_Other_NotAssigned},
+ {0xb47, 0xb48, HB_Mark_SpacingCombining},
+ {0xb49, 0xb4a, HB_Other_NotAssigned},
+ {0xb4b, 0xb4c, HB_Mark_SpacingCombining},
+ {0xb4d, 0xb4d, HB_Mark_NonSpacing},
+ {0xb4e, 0xb55, HB_Other_NotAssigned},
+ {0xb56, 0xb56, HB_Mark_NonSpacing},
+ {0xb57, 0xb57, HB_Mark_SpacingCombining},
+ {0xb58, 0xb5b, HB_Other_NotAssigned},
+ {0xb5c, 0xb5d, HB_Letter_Other},
+ {0xb5e, 0xb5e, HB_Other_NotAssigned},
+ {0xb5f, 0xb61, HB_Letter_Other},
+ {0xb62, 0xb63, HB_Mark_NonSpacing},
+ {0xb64, 0xb65, HB_Other_NotAssigned},
+ {0xb66, 0xb6f, HB_Number_DecimalDigit},
+ {0xb70, 0xb70, HB_Symbol_Other},
+ {0xb71, 0xb71, HB_Letter_Other},
+ {0xb72, 0xb81, HB_Other_NotAssigned},
+ {0xb82, 0xb82, HB_Mark_NonSpacing},
+ {0xb83, 0xb83, HB_Letter_Other},
+ {0xb84, 0xb84, HB_Other_NotAssigned},
+ {0xb85, 0xb8a, HB_Letter_Other},
+ {0xb8b, 0xb8d, HB_Other_NotAssigned},
+ {0xb8e, 0xb90, HB_Letter_Other},
+ {0xb91, 0xb91, HB_Other_NotAssigned},
+ {0xb92, 0xb95, HB_Letter_Other},
+ {0xb96, 0xb98, HB_Other_NotAssigned},
+ {0xb99, 0xb9a, HB_Letter_Other},
+ {0xb9b, 0xb9b, HB_Other_NotAssigned},
+ {0xb9c, 0xb9c, HB_Letter_Other},
+ {0xb9d, 0xb9d, HB_Other_NotAssigned},
+ {0xb9e, 0xb9f, HB_Letter_Other},
+ {0xba0, 0xba2, HB_Other_NotAssigned},
+ {0xba3, 0xba4, HB_Letter_Other},
+ {0xba5, 0xba7, HB_Other_NotAssigned},
+ {0xba8, 0xbaa, HB_Letter_Other},
+ {0xbab, 0xbad, HB_Other_NotAssigned},
+ {0xbae, 0xbb9, HB_Letter_Other},
+ {0xbba, 0xbbd, HB_Other_NotAssigned},
+ {0xbbe, 0xbbf, HB_Mark_SpacingCombining},
+ {0xbc0, 0xbc0, HB_Mark_NonSpacing},
+ {0xbc1, 0xbc2, HB_Mark_SpacingCombining},
+ {0xbc3, 0xbc5, HB_Other_NotAssigned},
+ {0xbc6, 0xbc8, HB_Mark_SpacingCombining},
+ {0xbc9, 0xbc9, HB_Other_NotAssigned},
+ {0xbca, 0xbcc, HB_Mark_SpacingCombining},
+ {0xbcd, 0xbcd, HB_Mark_NonSpacing},
+ {0xbce, 0xbcf, HB_Other_NotAssigned},
+ {0xbd0, 0xbd0, HB_Letter_Other},
+ {0xbd1, 0xbd6, HB_Other_NotAssigned},
+ {0xbd7, 0xbd7, HB_Mark_SpacingCombining},
+ {0xbd8, 0xbe5, HB_Other_NotAssigned},
+ {0xbe6, 0xbef, HB_Number_DecimalDigit},
+ {0xbf0, 0xbf2, HB_Number_Other},
+ {0xbf3, 0xbf8, HB_Symbol_Other},
+ {0xbf9, 0xbf9, HB_Symbol_Currency},
+ {0xbfa, 0xbfa, HB_Symbol_Other},
+ {0xbfb, 0xc00, HB_Other_NotAssigned},
+ {0xc01, 0xc03, HB_Mark_SpacingCombining},
+ {0xc04, 0xc04, HB_Other_NotAssigned},
+ {0xc05, 0xc0c, HB_Letter_Other},
+ {0xc0d, 0xc0d, HB_Other_NotAssigned},
+ {0xc0e, 0xc10, HB_Letter_Other},
+ {0xc11, 0xc11, HB_Other_NotAssigned},
+ {0xc12, 0xc28, HB_Letter_Other},
+ {0xc29, 0xc29, HB_Other_NotAssigned},
+ {0xc2a, 0xc33, HB_Letter_Other},
+ {0xc34, 0xc34, HB_Other_NotAssigned},
+ {0xc35, 0xc39, HB_Letter_Other},
+ {0xc3a, 0xc3c, HB_Other_NotAssigned},
+ {0xc3d, 0xc3d, HB_Letter_Other},
+ {0xc3e, 0xc40, HB_Mark_NonSpacing},
+ {0xc41, 0xc44, HB_Mark_SpacingCombining},
+ {0xc45, 0xc45, HB_Other_NotAssigned},
+ {0xc46, 0xc48, HB_Mark_NonSpacing},
+ {0xc49, 0xc49, HB_Other_NotAssigned},
+ {0xc4a, 0xc4d, HB_Mark_NonSpacing},
+ {0xc4e, 0xc54, HB_Other_NotAssigned},
+ {0xc55, 0xc56, HB_Mark_NonSpacing},
+ {0xc57, 0xc57, HB_Other_NotAssigned},
+ {0xc58, 0xc59, HB_Letter_Other},
+ {0xc5a, 0xc5f, HB_Other_NotAssigned},
+ {0xc60, 0xc61, HB_Letter_Other},
+ {0xc62, 0xc63, HB_Mark_NonSpacing},
+ {0xc64, 0xc65, HB_Other_NotAssigned},
+ {0xc66, 0xc6f, HB_Number_DecimalDigit},
+ {0xc70, 0xc77, HB_Other_NotAssigned},
+ {0xc78, 0xc7e, HB_Number_Other},
+ {0xc7f, 0xc7f, HB_Symbol_Other},
+ {0xc80, 0xc81, HB_Other_NotAssigned},
+ {0xc82, 0xc83, HB_Mark_SpacingCombining},
+ {0xc84, 0xc84, HB_Other_NotAssigned},
+ {0xc85, 0xc8c, HB_Letter_Other},
+ {0xc8d, 0xc8d, HB_Other_NotAssigned},
+ {0xc8e, 0xc90, HB_Letter_Other},
+ {0xc91, 0xc91, HB_Other_NotAssigned},
+ {0xc92, 0xca8, HB_Letter_Other},
+ {0xca9, 0xca9, HB_Other_NotAssigned},
+ {0xcaa, 0xcb3, HB_Letter_Other},
+ {0xcb4, 0xcb4, HB_Other_NotAssigned},
+ {0xcb5, 0xcb9, HB_Letter_Other},
+ {0xcba, 0xcbb, HB_Other_NotAssigned},
+ {0xcbc, 0xcbc, HB_Mark_NonSpacing},
+ {0xcbd, 0xcbd, HB_Letter_Other},
+ {0xcbe, 0xcbe, HB_Mark_SpacingCombining},
+ {0xcbf, 0xcbf, HB_Mark_NonSpacing},
+ {0xcc0, 0xcc4, HB_Mark_SpacingCombining},
+ {0xcc5, 0xcc5, HB_Other_NotAssigned},
+ {0xcc6, 0xcc6, HB_Mark_NonSpacing},
+ {0xcc7, 0xcc8, HB_Mark_SpacingCombining},
+ {0xcc9, 0xcc9, HB_Other_NotAssigned},
+ {0xcca, 0xccb, HB_Mark_SpacingCombining},
+ {0xccc, 0xccd, HB_Mark_NonSpacing},
+ {0xcce, 0xcd4, HB_Other_NotAssigned},
+ {0xcd5, 0xcd6, HB_Mark_SpacingCombining},
+ {0xcd7, 0xcdd, HB_Other_NotAssigned},
+ {0xcde, 0xcde, HB_Letter_Other},
+ {0xcdf, 0xcdf, HB_Other_NotAssigned},
+ {0xce0, 0xce1, HB_Letter_Other},
+ {0xce2, 0xce3, HB_Mark_NonSpacing},
+ {0xce4, 0xce5, HB_Other_NotAssigned},
+ {0xce6, 0xcef, HB_Number_DecimalDigit},
+ {0xcf0, 0xcf0, HB_Other_NotAssigned},
+ {0xcf1, 0xcf2, HB_Symbol_Other},
+ {0xcf3, 0xd01, HB_Other_NotAssigned},
+ {0xd02, 0xd03, HB_Mark_SpacingCombining},
+ {0xd04, 0xd04, HB_Other_NotAssigned},
+ {0xd05, 0xd0c, HB_Letter_Other},
+ {0xd0d, 0xd0d, HB_Other_NotAssigned},
+ {0xd0e, 0xd10, HB_Letter_Other},
+ {0xd11, 0xd11, HB_Other_NotAssigned},
+ {0xd12, 0xd28, HB_Letter_Other},
+ {0xd29, 0xd29, HB_Other_NotAssigned},
+ {0xd2a, 0xd39, HB_Letter_Other},
+ {0xd3a, 0xd3c, HB_Other_NotAssigned},
+ {0xd3d, 0xd3d, HB_Letter_Other},
+ {0xd3e, 0xd40, HB_Mark_SpacingCombining},
+ {0xd41, 0xd44, HB_Mark_NonSpacing},
+ {0xd45, 0xd45, HB_Other_NotAssigned},
+ {0xd46, 0xd48, HB_Mark_SpacingCombining},
+ {0xd49, 0xd49, HB_Other_NotAssigned},
+ {0xd4a, 0xd4c, HB_Mark_SpacingCombining},
+ {0xd4d, 0xd4d, HB_Mark_NonSpacing},
+ {0xd4e, 0xd56, HB_Other_NotAssigned},
+ {0xd57, 0xd57, HB_Mark_SpacingCombining},
+ {0xd58, 0xd5f, HB_Other_NotAssigned},
+ {0xd60, 0xd61, HB_Letter_Other},
+ {0xd62, 0xd63, HB_Mark_NonSpacing},
+ {0xd64, 0xd65, HB_Other_NotAssigned},
+ {0xd66, 0xd6f, HB_Number_DecimalDigit},
+ {0xd70, 0xd75, HB_Number_Other},
+ {0xd76, 0xd78, HB_Other_NotAssigned},
+ {0xd79, 0xd79, HB_Symbol_Other},
+ {0xd7a, 0xd7f, HB_Letter_Other},
+ {0xd80, 0xd81, HB_Other_NotAssigned},
+ {0xd82, 0xd83, HB_Mark_SpacingCombining},
+ {0xd84, 0xd84, HB_Other_NotAssigned},
+ {0xd85, 0xd96, HB_Letter_Other},
+ {0xd97, 0xd99, HB_Other_NotAssigned},
+ {0xd9a, 0xdb1, HB_Letter_Other},
+ {0xdb2, 0xdb2, HB_Other_NotAssigned},
+ {0xdb3, 0xdbb, HB_Letter_Other},
+ {0xdbc, 0xdbc, HB_Other_NotAssigned},
+ {0xdbd, 0xdbd, HB_Letter_Other},
+ {0xdbe, 0xdbf, HB_Other_NotAssigned},
+ {0xdc0, 0xdc6, HB_Letter_Other},
+ {0xdc7, 0xdc9, HB_Other_NotAssigned},
+ {0xdca, 0xdca, HB_Mark_NonSpacing},
+ {0xdcb, 0xdce, HB_Other_NotAssigned},
+ {0xdcf, 0xdd1, HB_Mark_SpacingCombining},
+ {0xdd2, 0xdd4, HB_Mark_NonSpacing},
+ {0xdd5, 0xdd5, HB_Other_NotAssigned},
+ {0xdd6, 0xdd6, HB_Mark_NonSpacing},
+ {0xdd7, 0xdd7, HB_Other_NotAssigned},
+ {0xdd8, 0xddf, HB_Mark_SpacingCombining},
+ {0xde0, 0xdf1, HB_Other_NotAssigned},
+ {0xdf2, 0xdf3, HB_Mark_SpacingCombining},
+ {0xdf4, 0xdf4, HB_Punctuation_Other},
+ {0xdf5, 0xe00, HB_Other_NotAssigned},
+ {0xe01, 0xe30, HB_Letter_Other},
+ {0xe31, 0xe31, HB_Mark_NonSpacing},
+ {0xe32, 0xe33, HB_Letter_Other},
+ {0xe34, 0xe3a, HB_Mark_NonSpacing},
+ {0xe3b, 0xe3e, HB_Other_NotAssigned},
+ {0xe3f, 0xe3f, HB_Symbol_Currency},
+ {0xe40, 0xe45, HB_Letter_Other},
+ {0xe46, 0xe46, HB_Letter_Modifier},
+ {0xe47, 0xe4e, HB_Mark_NonSpacing},
+ {0xe4f, 0xe4f, HB_Punctuation_Other},
+ {0xe50, 0xe59, HB_Number_DecimalDigit},
+ {0xe5a, 0xe5b, HB_Punctuation_Other},
+ {0xe5c, 0xe80, HB_Other_NotAssigned},
+ {0xe81, 0xe82, HB_Letter_Other},
+ {0xe83, 0xe83, HB_Other_NotAssigned},
+ {0xe84, 0xe84, HB_Letter_Other},
+ {0xe85, 0xe86, HB_Other_NotAssigned},
+ {0xe87, 0xe88, HB_Letter_Other},
+ {0xe89, 0xe89, HB_Other_NotAssigned},
+ {0xe8a, 0xe8a, HB_Letter_Other},
+ {0xe8b, 0xe8c, HB_Other_NotAssigned},
+ {0xe8d, 0xe8d, HB_Letter_Other},
+ {0xe8e, 0xe93, HB_Other_NotAssigned},
+ {0xe94, 0xe97, HB_Letter_Other},
+ {0xe98, 0xe98, HB_Other_NotAssigned},
+ {0xe99, 0xe9f, HB_Letter_Other},
+ {0xea0, 0xea0, HB_Other_NotAssigned},
+ {0xea1, 0xea3, HB_Letter_Other},
+ {0xea4, 0xea4, HB_Other_NotAssigned},
+ {0xea5, 0xea5, HB_Letter_Other},
+ {0xea6, 0xea6, HB_Other_NotAssigned},
+ {0xea7, 0xea7, HB_Letter_Other},
+ {0xea8, 0xea9, HB_Other_NotAssigned},
+ {0xeaa, 0xeab, HB_Letter_Other},
+ {0xeac, 0xeac, HB_Other_NotAssigned},
+ {0xead, 0xeb0, HB_Letter_Other},
+ {0xeb1, 0xeb1, HB_Mark_NonSpacing},
+ {0xeb2, 0xeb3, HB_Letter_Other},
+ {0xeb4, 0xeb9, HB_Mark_NonSpacing},
+ {0xeba, 0xeba, HB_Other_NotAssigned},
+ {0xebb, 0xebc, HB_Mark_NonSpacing},
+ {0xebd, 0xebd, HB_Letter_Other},
+ {0xebe, 0xebf, HB_Other_NotAssigned},
+ {0xec0, 0xec4, HB_Letter_Other},
+ {0xec5, 0xec5, HB_Other_NotAssigned},
+ {0xec6, 0xec6, HB_Letter_Modifier},
+ {0xec7, 0xec7, HB_Other_NotAssigned},
+ {0xec8, 0xecd, HB_Mark_NonSpacing},
+ {0xece, 0xecf, HB_Other_NotAssigned},
+ {0xed0, 0xed9, HB_Number_DecimalDigit},
+ {0xeda, 0xedb, HB_Other_NotAssigned},
+ {0xedc, 0xedd, HB_Letter_Other},
+ {0xede, 0xeff, HB_Other_NotAssigned},
+ {0xf00, 0xf00, HB_Letter_Other},
+ {0xf01, 0xf03, HB_Symbol_Other},
+ {0xf04, 0xf12, HB_Punctuation_Other},
+ {0xf13, 0xf17, HB_Symbol_Other},
+ {0xf18, 0xf19, HB_Mark_NonSpacing},
+ {0xf1a, 0xf1f, HB_Symbol_Other},
+ {0xf20, 0xf29, HB_Number_DecimalDigit},
+ {0xf2a, 0xf33, HB_Number_Other},
+ {0xf34, 0xf34, HB_Symbol_Other},
+ {0xf35, 0xf35, HB_Mark_NonSpacing},
+ {0xf36, 0xf36, HB_Symbol_Other},
+ {0xf37, 0xf37, HB_Mark_NonSpacing},
+ {0xf38, 0xf38, HB_Symbol_Other},
+ {0xf39, 0xf39, HB_Mark_NonSpacing},
+ {0xf3a, 0xf3a, HB_Punctuation_Open},
+ {0xf3b, 0xf3b, HB_Punctuation_Close},
+ {0xf3c, 0xf3c, HB_Punctuation_Open},
+ {0xf3d, 0xf3d, HB_Punctuation_Close},
+ {0xf3e, 0xf3f, HB_Mark_SpacingCombining},
+ {0xf40, 0xf47, HB_Letter_Other},
+ {0xf48, 0xf48, HB_Other_NotAssigned},
+ {0xf49, 0xf6c, HB_Letter_Other},
+ {0xf6d, 0xf70, HB_Other_NotAssigned},
+ {0xf71, 0xf7e, HB_Mark_NonSpacing},
+ {0xf7f, 0xf7f, HB_Mark_SpacingCombining},
+ {0xf80, 0xf84, HB_Mark_NonSpacing},
+ {0xf85, 0xf85, HB_Punctuation_Other},
+ {0xf86, 0xf87, HB_Mark_NonSpacing},
+ {0xf88, 0xf8b, HB_Letter_Other},
+ {0xf8c, 0xf8f, HB_Other_NotAssigned},
+ {0xf90, 0xf97, HB_Mark_NonSpacing},
+ {0xf98, 0xf98, HB_Other_NotAssigned},
+ {0xf99, 0xfbc, HB_Mark_NonSpacing},
+ {0xfbd, 0xfbd, HB_Other_NotAssigned},
+ {0xfbe, 0xfc5, HB_Symbol_Other},
+ {0xfc6, 0xfc6, HB_Mark_NonSpacing},
+ {0xfc7, 0xfcc, HB_Symbol_Other},
+ {0xfcd, 0xfcd, HB_Other_NotAssigned},
+ {0xfce, 0xfcf, HB_Symbol_Other},
+ {0xfd0, 0xfd4, HB_Punctuation_Other},
+ {0xfd5, 0xfff, HB_Other_NotAssigned},
+ {0x1000, 0x102a, HB_Letter_Other},
+ {0x102b, 0x102c, HB_Mark_SpacingCombining},
+ {0x102d, 0x1030, HB_Mark_NonSpacing},
+ {0x1031, 0x1031, HB_Mark_SpacingCombining},
+ {0x1032, 0x1037, HB_Mark_NonSpacing},
+ {0x1038, 0x1038, HB_Mark_SpacingCombining},
+ {0x1039, 0x103a, HB_Mark_NonSpacing},
+ {0x103b, 0x103c, HB_Mark_SpacingCombining},
+ {0x103d, 0x103e, HB_Mark_NonSpacing},
+ {0x103f, 0x103f, HB_Letter_Other},
+ {0x1040, 0x1049, HB_Number_DecimalDigit},
+ {0x104a, 0x104f, HB_Punctuation_Other},
+ {0x1050, 0x1055, HB_Letter_Other},
+ {0x1056, 0x1057, HB_Mark_SpacingCombining},
+ {0x1058, 0x1059, HB_Mark_NonSpacing},
+ {0x105a, 0x105d, HB_Letter_Other},
+ {0x105e, 0x1060, HB_Mark_NonSpacing},
+ {0x1061, 0x1061, HB_Letter_Other},
+ {0x1062, 0x1064, HB_Mark_SpacingCombining},
+ {0x1065, 0x1066, HB_Letter_Other},
+ {0x1067, 0x106d, HB_Mark_SpacingCombining},
+ {0x106e, 0x1070, HB_Letter_Other},
+ {0x1071, 0x1074, HB_Mark_NonSpacing},
+ {0x1075, 0x1081, HB_Letter_Other},
+ {0x1082, 0x1082, HB_Mark_NonSpacing},
+ {0x1083, 0x1084, HB_Mark_SpacingCombining},
+ {0x1085, 0x1086, HB_Mark_NonSpacing},
+ {0x1087, 0x108c, HB_Mark_SpacingCombining},
+ {0x108d, 0x108d, HB_Mark_NonSpacing},
+ {0x108e, 0x108e, HB_Letter_Other},
+ {0x108f, 0x108f, HB_Mark_SpacingCombining},
+ {0x1090, 0x1099, HB_Number_DecimalDigit},
+ {0x109a, 0x109d, HB_Other_NotAssigned},
+ {0x109e, 0x109f, HB_Symbol_Other},
+ {0x10a0, 0x10c5, HB_Letter_Uppercase},
+ {0x10c6, 0x10cf, HB_Other_NotAssigned},
+ {0x10d0, 0x10fa, HB_Letter_Other},
+ {0x10fb, 0x10fb, HB_Punctuation_Other},
+ {0x10fc, 0x10fc, HB_Letter_Modifier},
+ {0x10fd, 0x10ff, HB_Other_NotAssigned},
+ {0x1100, 0x1159, HB_Letter_Other},
+ {0x115a, 0x115e, HB_Other_NotAssigned},
+ {0x115f, 0x11a2, HB_Letter_Other},
+ {0x11a3, 0x11a7, HB_Other_NotAssigned},
+ {0x11a8, 0x11f9, HB_Letter_Other},
+ {0x11fa, 0x11ff, HB_Other_NotAssigned},
+ {0x1200, 0x1248, HB_Letter_Other},
+ {0x1249, 0x1249, HB_Other_NotAssigned},
+ {0x124a, 0x124d, HB_Letter_Other},
+ {0x124e, 0x124f, HB_Other_NotAssigned},
+ {0x1250, 0x1256, HB_Letter_Other},
+ {0x1257, 0x1257, HB_Other_NotAssigned},
+ {0x1258, 0x1258, HB_Letter_Other},
+ {0x1259, 0x1259, HB_Other_NotAssigned},
+ {0x125a, 0x125d, HB_Letter_Other},
+ {0x125e, 0x125f, HB_Other_NotAssigned},
+ {0x1260, 0x1288, HB_Letter_Other},
+ {0x1289, 0x1289, HB_Other_NotAssigned},
+ {0x128a, 0x128d, HB_Letter_Other},
+ {0x128e, 0x128f, HB_Other_NotAssigned},
+ {0x1290, 0x12b0, HB_Letter_Other},
+ {0x12b1, 0x12b1, HB_Other_NotAssigned},
+ {0x12b2, 0x12b5, HB_Letter_Other},
+ {0x12b6, 0x12b7, HB_Other_NotAssigned},
+ {0x12b8, 0x12be, HB_Letter_Other},
+ {0x12bf, 0x12bf, HB_Other_NotAssigned},
+ {0x12c0, 0x12c0, HB_Letter_Other},
+ {0x12c1, 0x12c1, HB_Other_NotAssigned},
+ {0x12c2, 0x12c5, HB_Letter_Other},
+ {0x12c6, 0x12c7, HB_Other_NotAssigned},
+ {0x12c8, 0x12d6, HB_Letter_Other},
+ {0x12d7, 0x12d7, HB_Other_NotAssigned},
+ {0x12d8, 0x1310, HB_Letter_Other},
+ {0x1311, 0x1311, HB_Other_NotAssigned},
+ {0x1312, 0x1315, HB_Letter_Other},
+ {0x1316, 0x1317, HB_Other_NotAssigned},
+ {0x1318, 0x135a, HB_Letter_Other},
+ {0x135b, 0x135e, HB_Other_NotAssigned},
+ {0x135f, 0x135f, HB_Mark_NonSpacing},
+ {0x1360, 0x1360, HB_Symbol_Other},
+ {0x1361, 0x1368, HB_Punctuation_Other},
+ {0x1369, 0x137c, HB_Number_Other},
+ {0x137d, 0x137f, HB_Other_NotAssigned},
+ {0x1380, 0x138f, HB_Letter_Other},
+ {0x1390, 0x1399, HB_Symbol_Other},
+ {0x139a, 0x139f, HB_Other_NotAssigned},
+ {0x13a0, 0x13f4, HB_Letter_Other},
+ {0x13f5, 0x1400, HB_Other_NotAssigned},
+ {0x1401, 0x166c, HB_Letter_Other},
+ {0x166d, 0x166e, HB_Punctuation_Other},
+ {0x166f, 0x1676, HB_Letter_Other},
+ {0x1677, 0x167f, HB_Other_NotAssigned},
+ {0x1680, 0x1680, HB_Separator_Space},
+ {0x1681, 0x169a, HB_Letter_Other},
+ {0x169b, 0x169b, HB_Punctuation_Open},
+ {0x169c, 0x169c, HB_Punctuation_Close},
+ {0x169d, 0x169f, HB_Other_NotAssigned},
+ {0x16a0, 0x16ea, HB_Letter_Other},
+ {0x16eb, 0x16ed, HB_Punctuation_Other},
+ {0x16ee, 0x16f0, HB_Number_Letter},
+ {0x16f1, 0x16ff, HB_Other_NotAssigned},
+ {0x1700, 0x170c, HB_Letter_Other},
+ {0x170d, 0x170d, HB_Other_NotAssigned},
+ {0x170e, 0x1711, HB_Letter_Other},
+ {0x1712, 0x1714, HB_Mark_NonSpacing},
+ {0x1715, 0x171f, HB_Other_NotAssigned},
+ {0x1720, 0x1731, HB_Letter_Other},
+ {0x1732, 0x1734, HB_Mark_NonSpacing},
+ {0x1735, 0x1736, HB_Punctuation_Other},
+ {0x1737, 0x173f, HB_Other_NotAssigned},
+ {0x1740, 0x1751, HB_Letter_Other},
+ {0x1752, 0x1753, HB_Mark_NonSpacing},
+ {0x1754, 0x175f, HB_Other_NotAssigned},
+ {0x1760, 0x176c, HB_Letter_Other},
+ {0x176d, 0x176d, HB_Other_NotAssigned},
+ {0x176e, 0x1770, HB_Letter_Other},
+ {0x1771, 0x1771, HB_Other_NotAssigned},
+ {0x1772, 0x1773, HB_Mark_NonSpacing},
+ {0x1774, 0x177f, HB_Other_NotAssigned},
+ {0x1780, 0x17b3, HB_Letter_Other},
+ {0x17b4, 0x17b5, HB_Other_Format},
+ {0x17b6, 0x17b6, HB_Mark_SpacingCombining},
+ {0x17b7, 0x17bd, HB_Mark_NonSpacing},
+ {0x17be, 0x17c5, HB_Mark_SpacingCombining},
+ {0x17c6, 0x17c6, HB_Mark_NonSpacing},
+ {0x17c7, 0x17c8, HB_Mark_SpacingCombining},
+ {0x17c9, 0x17d3, HB_Mark_NonSpacing},
+ {0x17d4, 0x17d6, HB_Punctuation_Other},
+ {0x17d7, 0x17d7, HB_Letter_Modifier},
+ {0x17d8, 0x17da, HB_Punctuation_Other},
+ {0x17db, 0x17db, HB_Symbol_Currency},
+ {0x17dc, 0x17dc, HB_Letter_Other},
+ {0x17dd, 0x17dd, HB_Mark_NonSpacing},
+ {0x17de, 0x17df, HB_Other_NotAssigned},
+ {0x17e0, 0x17e9, HB_Number_DecimalDigit},
+ {0x17ea, 0x17ef, HB_Other_NotAssigned},
+ {0x17f0, 0x17f9, HB_Number_Other},
+ {0x17fa, 0x17ff, HB_Other_NotAssigned},
+ {0x1800, 0x1805, HB_Punctuation_Other},
+ {0x1806, 0x1806, HB_Punctuation_Dash},
+ {0x1807, 0x180a, HB_Punctuation_Other},
+ {0x180b, 0x180d, HB_Mark_NonSpacing},
+ {0x180e, 0x180e, HB_Separator_Space},
+ {0x180f, 0x180f, HB_Other_NotAssigned},
+ {0x1810, 0x1819, HB_Number_DecimalDigit},
+ {0x181a, 0x181f, HB_Other_NotAssigned},
+ {0x1820, 0x1842, HB_Letter_Other},
+ {0x1843, 0x1843, HB_Letter_Modifier},
+ {0x1844, 0x1877, HB_Letter_Other},
+ {0x1878, 0x187f, HB_Other_NotAssigned},
+ {0x1880, 0x18a8, HB_Letter_Other},
+ {0x18a9, 0x18a9, HB_Mark_NonSpacing},
+ {0x18aa, 0x18aa, HB_Letter_Other},
+ {0x18ab, 0x18ff, HB_Other_NotAssigned},
+ {0x1900, 0x191c, HB_Letter_Other},
+ {0x191d, 0x191f, HB_Other_NotAssigned},
+ {0x1920, 0x1922, HB_Mark_NonSpacing},
+ {0x1923, 0x1926, HB_Mark_SpacingCombining},
+ {0x1927, 0x1928, HB_Mark_NonSpacing},
+ {0x1929, 0x192b, HB_Mark_SpacingCombining},
+ {0x192c, 0x192f, HB_Other_NotAssigned},
+ {0x1930, 0x1931, HB_Mark_SpacingCombining},
+ {0x1932, 0x1932, HB_Mark_NonSpacing},
+ {0x1933, 0x1938, HB_Mark_SpacingCombining},
+ {0x1939, 0x193b, HB_Mark_NonSpacing},
+ {0x193c, 0x193f, HB_Other_NotAssigned},
+ {0x1940, 0x1940, HB_Symbol_Other},
+ {0x1941, 0x1943, HB_Other_NotAssigned},
+ {0x1944, 0x1945, HB_Punctuation_Other},
+ {0x1946, 0x194f, HB_Number_DecimalDigit},
+ {0x1950, 0x196d, HB_Letter_Other},
+ {0x196e, 0x196f, HB_Other_NotAssigned},
+ {0x1970, 0x1974, HB_Letter_Other},
+ {0x1975, 0x197f, HB_Other_NotAssigned},
+ {0x1980, 0x19a9, HB_Letter_Other},
+ {0x19aa, 0x19af, HB_Other_NotAssigned},
+ {0x19b0, 0x19c0, HB_Mark_SpacingCombining},
+ {0x19c1, 0x19c7, HB_Letter_Other},
+ {0x19c8, 0x19c9, HB_Mark_SpacingCombining},
+ {0x19ca, 0x19cf, HB_Other_NotAssigned},
+ {0x19d0, 0x19d9, HB_Number_DecimalDigit},
+ {0x19da, 0x19dd, HB_Other_NotAssigned},
+ {0x19de, 0x19df, HB_Punctuation_Other},
+ {0x19e0, 0x19ff, HB_Symbol_Other},
+ {0x1a00, 0x1a16, HB_Letter_Other},
+ {0x1a17, 0x1a18, HB_Mark_NonSpacing},
+ {0x1a19, 0x1a1b, HB_Mark_SpacingCombining},
+ {0x1a1c, 0x1a1d, HB_Other_NotAssigned},
+ {0x1a1e, 0x1a1f, HB_Punctuation_Other},
+ {0x1a20, 0x1aff, HB_Other_NotAssigned},
+ {0x1b00, 0x1b03, HB_Mark_NonSpacing},
+ {0x1b04, 0x1b04, HB_Mark_SpacingCombining},
+ {0x1b05, 0x1b33, HB_Letter_Other},
+ {0x1b34, 0x1b34, HB_Mark_NonSpacing},
+ {0x1b35, 0x1b35, HB_Mark_SpacingCombining},
+ {0x1b36, 0x1b3a, HB_Mark_NonSpacing},
+ {0x1b3b, 0x1b3b, HB_Mark_SpacingCombining},
+ {0x1b3c, 0x1b3c, HB_Mark_NonSpacing},
+ {0x1b3d, 0x1b41, HB_Mark_SpacingCombining},
+ {0x1b42, 0x1b42, HB_Mark_NonSpacing},
+ {0x1b43, 0x1b44, HB_Mark_SpacingCombining},
+ {0x1b45, 0x1b4b, HB_Letter_Other},
+ {0x1b4c, 0x1b4f, HB_Other_NotAssigned},
+ {0x1b50, 0x1b59, HB_Number_DecimalDigit},
+ {0x1b5a, 0x1b60, HB_Punctuation_Other},
+ {0x1b61, 0x1b6a, HB_Symbol_Other},
+ {0x1b6b, 0x1b73, HB_Mark_NonSpacing},
+ {0x1b74, 0x1b7c, HB_Symbol_Other},
+ {0x1b7d, 0x1b7f, HB_Other_NotAssigned},
+ {0x1b80, 0x1b81, HB_Mark_NonSpacing},
+ {0x1b82, 0x1b82, HB_Mark_SpacingCombining},
+ {0x1b83, 0x1ba0, HB_Letter_Other},
+ {0x1ba1, 0x1ba1, HB_Mark_SpacingCombining},
+ {0x1ba2, 0x1ba5, HB_Mark_NonSpacing},
+ {0x1ba6, 0x1ba7, HB_Mark_SpacingCombining},
+ {0x1ba8, 0x1ba9, HB_Mark_NonSpacing},
+ {0x1baa, 0x1baa, HB_Mark_SpacingCombining},
+ {0x1bab, 0x1bad, HB_Other_NotAssigned},
+ {0x1bae, 0x1baf, HB_Letter_Other},
+ {0x1bb0, 0x1bb9, HB_Number_DecimalDigit},
+ {0x1bba, 0x1bff, HB_Other_NotAssigned},
+ {0x1c00, 0x1c23, HB_Letter_Other},
+ {0x1c24, 0x1c2b, HB_Mark_SpacingCombining},
+ {0x1c2c, 0x1c33, HB_Mark_NonSpacing},
+ {0x1c34, 0x1c35, HB_Mark_SpacingCombining},
+ {0x1c36, 0x1c37, HB_Mark_NonSpacing},
+ {0x1c38, 0x1c3a, HB_Other_NotAssigned},
+ {0x1c3b, 0x1c3f, HB_Punctuation_Other},
+ {0x1c40, 0x1c49, HB_Number_DecimalDigit},
+ {0x1c4a, 0x1c4c, HB_Other_NotAssigned},
+ {0x1c4d, 0x1c4f, HB_Letter_Other},
+ {0x1c50, 0x1c59, HB_Number_DecimalDigit},
+ {0x1c5a, 0x1c77, HB_Letter_Other},
+ {0x1c78, 0x1c7d, HB_Letter_Modifier},
+ {0x1c7e, 0x1c7f, HB_Punctuation_Other},
+ {0x1c80, 0x1cff, HB_Other_NotAssigned},
+ {0x1d00, 0x1d2b, HB_Letter_Lowercase},
+ {0x1d2c, 0x1d61, HB_Letter_Modifier},
+ {0x1d62, 0x1d77, HB_Letter_Lowercase},
+ {0x1d78, 0x1d78, HB_Letter_Modifier},
+ {0x1d79, 0x1d9a, HB_Letter_Lowercase},
+ {0x1d9b, 0x1dbf, HB_Letter_Modifier},
+ {0x1dc0, 0x1de6, HB_Mark_NonSpacing},
+ {0x1de7, 0x1dfd, HB_Other_NotAssigned},
+ {0x1dfe, 0x1dff, HB_Mark_NonSpacing},
+ {0x1e00, 0x1e00, HB_Letter_Uppercase},
+ {0x1e01, 0x1e01, HB_Letter_Lowercase},
+ {0x1e02, 0x1e02, HB_Letter_Uppercase},
+ {0x1e03, 0x1e03, HB_Letter_Lowercase},
+ {0x1e04, 0x1e04, HB_Letter_Uppercase},
+ {0x1e05, 0x1e05, HB_Letter_Lowercase},
+ {0x1e06, 0x1e06, HB_Letter_Uppercase},
+ {0x1e07, 0x1e07, HB_Letter_Lowercase},
+ {0x1e08, 0x1e08, HB_Letter_Uppercase},
+ {0x1e09, 0x1e09, HB_Letter_Lowercase},
+ {0x1e0a, 0x1e0a, HB_Letter_Uppercase},
+ {0x1e0b, 0x1e0b, HB_Letter_Lowercase},
+ {0x1e0c, 0x1e0c, HB_Letter_Uppercase},
+ {0x1e0d, 0x1e0d, HB_Letter_Lowercase},
+ {0x1e0e, 0x1e0e, HB_Letter_Uppercase},
+ {0x1e0f, 0x1e0f, HB_Letter_Lowercase},
+ {0x1e10, 0x1e10, HB_Letter_Uppercase},
+ {0x1e11, 0x1e11, HB_Letter_Lowercase},
+ {0x1e12, 0x1e12, HB_Letter_Uppercase},
+ {0x1e13, 0x1e13, HB_Letter_Lowercase},
+ {0x1e14, 0x1e14, HB_Letter_Uppercase},
+ {0x1e15, 0x1e15, HB_Letter_Lowercase},
+ {0x1e16, 0x1e16, HB_Letter_Uppercase},
+ {0x1e17, 0x1e17, HB_Letter_Lowercase},
+ {0x1e18, 0x1e18, HB_Letter_Uppercase},
+ {0x1e19, 0x1e19, HB_Letter_Lowercase},
+ {0x1e1a, 0x1e1a, HB_Letter_Uppercase},
+ {0x1e1b, 0x1e1b, HB_Letter_Lowercase},
+ {0x1e1c, 0x1e1c, HB_Letter_Uppercase},
+ {0x1e1d, 0x1e1d, HB_Letter_Lowercase},
+ {0x1e1e, 0x1e1e, HB_Letter_Uppercase},
+ {0x1e1f, 0x1e1f, HB_Letter_Lowercase},
+ {0x1e20, 0x1e20, HB_Letter_Uppercase},
+ {0x1e21, 0x1e21, HB_Letter_Lowercase},
+ {0x1e22, 0x1e22, HB_Letter_Uppercase},
+ {0x1e23, 0x1e23, HB_Letter_Lowercase},
+ {0x1e24, 0x1e24, HB_Letter_Uppercase},
+ {0x1e25, 0x1e25, HB_Letter_Lowercase},
+ {0x1e26, 0x1e26, HB_Letter_Uppercase},
+ {0x1e27, 0x1e27, HB_Letter_Lowercase},
+ {0x1e28, 0x1e28, HB_Letter_Uppercase},
+ {0x1e29, 0x1e29, HB_Letter_Lowercase},
+ {0x1e2a, 0x1e2a, HB_Letter_Uppercase},
+ {0x1e2b, 0x1e2b, HB_Letter_Lowercase},
+ {0x1e2c, 0x1e2c, HB_Letter_Uppercase},
+ {0x1e2d, 0x1e2d, HB_Letter_Lowercase},
+ {0x1e2e, 0x1e2e, HB_Letter_Uppercase},
+ {0x1e2f, 0x1e2f, HB_Letter_Lowercase},
+ {0x1e30, 0x1e30, HB_Letter_Uppercase},
+ {0x1e31, 0x1e31, HB_Letter_Lowercase},
+ {0x1e32, 0x1e32, HB_Letter_Uppercase},
+ {0x1e33, 0x1e33, HB_Letter_Lowercase},
+ {0x1e34, 0x1e34, HB_Letter_Uppercase},
+ {0x1e35, 0x1e35, HB_Letter_Lowercase},
+ {0x1e36, 0x1e36, HB_Letter_Uppercase},
+ {0x1e37, 0x1e37, HB_Letter_Lowercase},
+ {0x1e38, 0x1e38, HB_Letter_Uppercase},
+ {0x1e39, 0x1e39, HB_Letter_Lowercase},
+ {0x1e3a, 0x1e3a, HB_Letter_Uppercase},
+ {0x1e3b, 0x1e3b, HB_Letter_Lowercase},
+ {0x1e3c, 0x1e3c, HB_Letter_Uppercase},
+ {0x1e3d, 0x1e3d, HB_Letter_Lowercase},
+ {0x1e3e, 0x1e3e, HB_Letter_Uppercase},
+ {0x1e3f, 0x1e3f, HB_Letter_Lowercase},
+ {0x1e40, 0x1e40, HB_Letter_Uppercase},
+ {0x1e41, 0x1e41, HB_Letter_Lowercase},
+ {0x1e42, 0x1e42, HB_Letter_Uppercase},
+ {0x1e43, 0x1e43, HB_Letter_Lowercase},
+ {0x1e44, 0x1e44, HB_Letter_Uppercase},
+ {0x1e45, 0x1e45, HB_Letter_Lowercase},
+ {0x1e46, 0x1e46, HB_Letter_Uppercase},
+ {0x1e47, 0x1e47, HB_Letter_Lowercase},
+ {0x1e48, 0x1e48, HB_Letter_Uppercase},
+ {0x1e49, 0x1e49, HB_Letter_Lowercase},
+ {0x1e4a, 0x1e4a, HB_Letter_Uppercase},
+ {0x1e4b, 0x1e4b, HB_Letter_Lowercase},
+ {0x1e4c, 0x1e4c, HB_Letter_Uppercase},
+ {0x1e4d, 0x1e4d, HB_Letter_Lowercase},
+ {0x1e4e, 0x1e4e, HB_Letter_Uppercase},
+ {0x1e4f, 0x1e4f, HB_Letter_Lowercase},
+ {0x1e50, 0x1e50, HB_Letter_Uppercase},
+ {0x1e51, 0x1e51, HB_Letter_Lowercase},
+ {0x1e52, 0x1e52, HB_Letter_Uppercase},
+ {0x1e53, 0x1e53, HB_Letter_Lowercase},
+ {0x1e54, 0x1e54, HB_Letter_Uppercase},
+ {0x1e55, 0x1e55, HB_Letter_Lowercase},
+ {0x1e56, 0x1e56, HB_Letter_Uppercase},
+ {0x1e57, 0x1e57, HB_Letter_Lowercase},
+ {0x1e58, 0x1e58, HB_Letter_Uppercase},
+ {0x1e59, 0x1e59, HB_Letter_Lowercase},
+ {0x1e5a, 0x1e5a, HB_Letter_Uppercase},
+ {0x1e5b, 0x1e5b, HB_Letter_Lowercase},
+ {0x1e5c, 0x1e5c, HB_Letter_Uppercase},
+ {0x1e5d, 0x1e5d, HB_Letter_Lowercase},
+ {0x1e5e, 0x1e5e, HB_Letter_Uppercase},
+ {0x1e5f, 0x1e5f, HB_Letter_Lowercase},
+ {0x1e60, 0x1e60, HB_Letter_Uppercase},
+ {0x1e61, 0x1e61, HB_Letter_Lowercase},
+ {0x1e62, 0x1e62, HB_Letter_Uppercase},
+ {0x1e63, 0x1e63, HB_Letter_Lowercase},
+ {0x1e64, 0x1e64, HB_Letter_Uppercase},
+ {0x1e65, 0x1e65, HB_Letter_Lowercase},
+ {0x1e66, 0x1e66, HB_Letter_Uppercase},
+ {0x1e67, 0x1e67, HB_Letter_Lowercase},
+ {0x1e68, 0x1e68, HB_Letter_Uppercase},
+ {0x1e69, 0x1e69, HB_Letter_Lowercase},
+ {0x1e6a, 0x1e6a, HB_Letter_Uppercase},
+ {0x1e6b, 0x1e6b, HB_Letter_Lowercase},
+ {0x1e6c, 0x1e6c, HB_Letter_Uppercase},
+ {0x1e6d, 0x1e6d, HB_Letter_Lowercase},
+ {0x1e6e, 0x1e6e, HB_Letter_Uppercase},
+ {0x1e6f, 0x1e6f, HB_Letter_Lowercase},
+ {0x1e70, 0x1e70, HB_Letter_Uppercase},
+ {0x1e71, 0x1e71, HB_Letter_Lowercase},
+ {0x1e72, 0x1e72, HB_Letter_Uppercase},
+ {0x1e73, 0x1e73, HB_Letter_Lowercase},
+ {0x1e74, 0x1e74, HB_Letter_Uppercase},
+ {0x1e75, 0x1e75, HB_Letter_Lowercase},
+ {0x1e76, 0x1e76, HB_Letter_Uppercase},
+ {0x1e77, 0x1e77, HB_Letter_Lowercase},
+ {0x1e78, 0x1e78, HB_Letter_Uppercase},
+ {0x1e79, 0x1e79, HB_Letter_Lowercase},
+ {0x1e7a, 0x1e7a, HB_Letter_Uppercase},
+ {0x1e7b, 0x1e7b, HB_Letter_Lowercase},
+ {0x1e7c, 0x1e7c, HB_Letter_Uppercase},
+ {0x1e7d, 0x1e7d, HB_Letter_Lowercase},
+ {0x1e7e, 0x1e7e, HB_Letter_Uppercase},
+ {0x1e7f, 0x1e7f, HB_Letter_Lowercase},
+ {0x1e80, 0x1e80, HB_Letter_Uppercase},
+ {0x1e81, 0x1e81, HB_Letter_Lowercase},
+ {0x1e82, 0x1e82, HB_Letter_Uppercase},
+ {0x1e83, 0x1e83, HB_Letter_Lowercase},
+ {0x1e84, 0x1e84, HB_Letter_Uppercase},
+ {0x1e85, 0x1e85, HB_Letter_Lowercase},
+ {0x1e86, 0x1e86, HB_Letter_Uppercase},
+ {0x1e87, 0x1e87, HB_Letter_Lowercase},
+ {0x1e88, 0x1e88, HB_Letter_Uppercase},
+ {0x1e89, 0x1e89, HB_Letter_Lowercase},
+ {0x1e8a, 0x1e8a, HB_Letter_Uppercase},
+ {0x1e8b, 0x1e8b, HB_Letter_Lowercase},
+ {0x1e8c, 0x1e8c, HB_Letter_Uppercase},
+ {0x1e8d, 0x1e8d, HB_Letter_Lowercase},
+ {0x1e8e, 0x1e8e, HB_Letter_Uppercase},
+ {0x1e8f, 0x1e8f, HB_Letter_Lowercase},
+ {0x1e90, 0x1e90, HB_Letter_Uppercase},
+ {0x1e91, 0x1e91, HB_Letter_Lowercase},
+ {0x1e92, 0x1e92, HB_Letter_Uppercase},
+ {0x1e93, 0x1e93, HB_Letter_Lowercase},
+ {0x1e94, 0x1e94, HB_Letter_Uppercase},
+ {0x1e95, 0x1e9d, HB_Letter_Lowercase},
+ {0x1e9e, 0x1e9e, HB_Letter_Uppercase},
+ {0x1e9f, 0x1e9f, HB_Letter_Lowercase},
+ {0x1ea0, 0x1ea0, HB_Letter_Uppercase},
+ {0x1ea1, 0x1ea1, HB_Letter_Lowercase},
+ {0x1ea2, 0x1ea2, HB_Letter_Uppercase},
+ {0x1ea3, 0x1ea3, HB_Letter_Lowercase},
+ {0x1ea4, 0x1ea4, HB_Letter_Uppercase},
+ {0x1ea5, 0x1ea5, HB_Letter_Lowercase},
+ {0x1ea6, 0x1ea6, HB_Letter_Uppercase},
+ {0x1ea7, 0x1ea7, HB_Letter_Lowercase},
+ {0x1ea8, 0x1ea8, HB_Letter_Uppercase},
+ {0x1ea9, 0x1ea9, HB_Letter_Lowercase},
+ {0x1eaa, 0x1eaa, HB_Letter_Uppercase},
+ {0x1eab, 0x1eab, HB_Letter_Lowercase},
+ {0x1eac, 0x1eac, HB_Letter_Uppercase},
+ {0x1ead, 0x1ead, HB_Letter_Lowercase},
+ {0x1eae, 0x1eae, HB_Letter_Uppercase},
+ {0x1eaf, 0x1eaf, HB_Letter_Lowercase},
+ {0x1eb0, 0x1eb0, HB_Letter_Uppercase},
+ {0x1eb1, 0x1eb1, HB_Letter_Lowercase},
+ {0x1eb2, 0x1eb2, HB_Letter_Uppercase},
+ {0x1eb3, 0x1eb3, HB_Letter_Lowercase},
+ {0x1eb4, 0x1eb4, HB_Letter_Uppercase},
+ {0x1eb5, 0x1eb5, HB_Letter_Lowercase},
+ {0x1eb6, 0x1eb6, HB_Letter_Uppercase},
+ {0x1eb7, 0x1eb7, HB_Letter_Lowercase},
+ {0x1eb8, 0x1eb8, HB_Letter_Uppercase},
+ {0x1eb9, 0x1eb9, HB_Letter_Lowercase},
+ {0x1eba, 0x1eba, HB_Letter_Uppercase},
+ {0x1ebb, 0x1ebb, HB_Letter_Lowercase},
+ {0x1ebc, 0x1ebc, HB_Letter_Uppercase},
+ {0x1ebd, 0x1ebd, HB_Letter_Lowercase},
+ {0x1ebe, 0x1ebe, HB_Letter_Uppercase},
+ {0x1ebf, 0x1ebf, HB_Letter_Lowercase},
+ {0x1ec0, 0x1ec0, HB_Letter_Uppercase},
+ {0x1ec1, 0x1ec1, HB_Letter_Lowercase},
+ {0x1ec2, 0x1ec2, HB_Letter_Uppercase},
+ {0x1ec3, 0x1ec3, HB_Letter_Lowercase},
+ {0x1ec4, 0x1ec4, HB_Letter_Uppercase},
+ {0x1ec5, 0x1ec5, HB_Letter_Lowercase},
+ {0x1ec6, 0x1ec6, HB_Letter_Uppercase},
+ {0x1ec7, 0x1ec7, HB_Letter_Lowercase},
+ {0x1ec8, 0x1ec8, HB_Letter_Uppercase},
+ {0x1ec9, 0x1ec9, HB_Letter_Lowercase},
+ {0x1eca, 0x1eca, HB_Letter_Uppercase},
+ {0x1ecb, 0x1ecb, HB_Letter_Lowercase},
+ {0x1ecc, 0x1ecc, HB_Letter_Uppercase},
+ {0x1ecd, 0x1ecd, HB_Letter_Lowercase},
+ {0x1ece, 0x1ece, HB_Letter_Uppercase},
+ {0x1ecf, 0x1ecf, HB_Letter_Lowercase},
+ {0x1ed0, 0x1ed0, HB_Letter_Uppercase},
+ {0x1ed1, 0x1ed1, HB_Letter_Lowercase},
+ {0x1ed2, 0x1ed2, HB_Letter_Uppercase},
+ {0x1ed3, 0x1ed3, HB_Letter_Lowercase},
+ {0x1ed4, 0x1ed4, HB_Letter_Uppercase},
+ {0x1ed5, 0x1ed5, HB_Letter_Lowercase},
+ {0x1ed6, 0x1ed6, HB_Letter_Uppercase},
+ {0x1ed7, 0x1ed7, HB_Letter_Lowercase},
+ {0x1ed8, 0x1ed8, HB_Letter_Uppercase},
+ {0x1ed9, 0x1ed9, HB_Letter_Lowercase},
+ {0x1eda, 0x1eda, HB_Letter_Uppercase},
+ {0x1edb, 0x1edb, HB_Letter_Lowercase},
+ {0x1edc, 0x1edc, HB_Letter_Uppercase},
+ {0x1edd, 0x1edd, HB_Letter_Lowercase},
+ {0x1ede, 0x1ede, HB_Letter_Uppercase},
+ {0x1edf, 0x1edf, HB_Letter_Lowercase},
+ {0x1ee0, 0x1ee0, HB_Letter_Uppercase},
+ {0x1ee1, 0x1ee1, HB_Letter_Lowercase},
+ {0x1ee2, 0x1ee2, HB_Letter_Uppercase},
+ {0x1ee3, 0x1ee3, HB_Letter_Lowercase},
+ {0x1ee4, 0x1ee4, HB_Letter_Uppercase},
+ {0x1ee5, 0x1ee5, HB_Letter_Lowercase},
+ {0x1ee6, 0x1ee6, HB_Letter_Uppercase},
+ {0x1ee7, 0x1ee7, HB_Letter_Lowercase},
+ {0x1ee8, 0x1ee8, HB_Letter_Uppercase},
+ {0x1ee9, 0x1ee9, HB_Letter_Lowercase},
+ {0x1eea, 0x1eea, HB_Letter_Uppercase},
+ {0x1eeb, 0x1eeb, HB_Letter_Lowercase},
+ {0x1eec, 0x1eec, HB_Letter_Uppercase},
+ {0x1eed, 0x1eed, HB_Letter_Lowercase},
+ {0x1eee, 0x1eee, HB_Letter_Uppercase},
+ {0x1eef, 0x1eef, HB_Letter_Lowercase},
+ {0x1ef0, 0x1ef0, HB_Letter_Uppercase},
+ {0x1ef1, 0x1ef1, HB_Letter_Lowercase},
+ {0x1ef2, 0x1ef2, HB_Letter_Uppercase},
+ {0x1ef3, 0x1ef3, HB_Letter_Lowercase},
+ {0x1ef4, 0x1ef4, HB_Letter_Uppercase},
+ {0x1ef5, 0x1ef5, HB_Letter_Lowercase},
+ {0x1ef6, 0x1ef6, HB_Letter_Uppercase},
+ {0x1ef7, 0x1ef7, HB_Letter_Lowercase},
+ {0x1ef8, 0x1ef8, HB_Letter_Uppercase},
+ {0x1ef9, 0x1ef9, HB_Letter_Lowercase},
+ {0x1efa, 0x1efa, HB_Letter_Uppercase},
+ {0x1efb, 0x1efb, HB_Letter_Lowercase},
+ {0x1efc, 0x1efc, HB_Letter_Uppercase},
+ {0x1efd, 0x1efd, HB_Letter_Lowercase},
+ {0x1efe, 0x1efe, HB_Letter_Uppercase},
+ {0x1eff, 0x1f07, HB_Letter_Lowercase},
+ {0x1f08, 0x1f0f, HB_Letter_Uppercase},
+ {0x1f10, 0x1f15, HB_Letter_Lowercase},
+ {0x1f16, 0x1f17, HB_Other_NotAssigned},
+ {0x1f18, 0x1f1d, HB_Letter_Uppercase},
+ {0x1f1e, 0x1f1f, HB_Other_NotAssigned},
+ {0x1f20, 0x1f27, HB_Letter_Lowercase},
+ {0x1f28, 0x1f2f, HB_Letter_Uppercase},
+ {0x1f30, 0x1f37, HB_Letter_Lowercase},
+ {0x1f38, 0x1f3f, HB_Letter_Uppercase},
+ {0x1f40, 0x1f45, HB_Letter_Lowercase},
+ {0x1f46, 0x1f47, HB_Other_NotAssigned},
+ {0x1f48, 0x1f4d, HB_Letter_Uppercase},
+ {0x1f4e, 0x1f4f, HB_Other_NotAssigned},
+ {0x1f50, 0x1f57, HB_Letter_Lowercase},
+ {0x1f58, 0x1f58, HB_Other_NotAssigned},
+ {0x1f59, 0x1f59, HB_Letter_Uppercase},
+ {0x1f5a, 0x1f5a, HB_Other_NotAssigned},
+ {0x1f5b, 0x1f5b, HB_Letter_Uppercase},
+ {0x1f5c, 0x1f5c, HB_Other_NotAssigned},
+ {0x1f5d, 0x1f5d, HB_Letter_Uppercase},
+ {0x1f5e, 0x1f5e, HB_Other_NotAssigned},
+ {0x1f5f, 0x1f5f, HB_Letter_Uppercase},
+ {0x1f60, 0x1f67, HB_Letter_Lowercase},
+ {0x1f68, 0x1f6f, HB_Letter_Uppercase},
+ {0x1f70, 0x1f7d, HB_Letter_Lowercase},
+ {0x1f7e, 0x1f7f, HB_Other_NotAssigned},
+ {0x1f80, 0x1f87, HB_Letter_Lowercase},
+ {0x1f88, 0x1f8f, HB_Letter_Titlecase},
+ {0x1f90, 0x1f97, HB_Letter_Lowercase},
+ {0x1f98, 0x1f9f, HB_Letter_Titlecase},
+ {0x1fa0, 0x1fa7, HB_Letter_Lowercase},
+ {0x1fa8, 0x1faf, HB_Letter_Titlecase},
+ {0x1fb0, 0x1fb4, HB_Letter_Lowercase},
+ {0x1fb5, 0x1fb5, HB_Other_NotAssigned},
+ {0x1fb6, 0x1fb7, HB_Letter_Lowercase},
+ {0x1fb8, 0x1fbb, HB_Letter_Uppercase},
+ {0x1fbc, 0x1fbc, HB_Letter_Titlecase},
+ {0x1fbd, 0x1fbd, HB_Symbol_Modifier},
+ {0x1fbe, 0x1fbe, HB_Letter_Lowercase},
+ {0x1fbf, 0x1fc1, HB_Symbol_Modifier},
+ {0x1fc2, 0x1fc4, HB_Letter_Lowercase},
+ {0x1fc5, 0x1fc5, HB_Other_NotAssigned},
+ {0x1fc6, 0x1fc7, HB_Letter_Lowercase},
+ {0x1fc8, 0x1fcb, HB_Letter_Uppercase},
+ {0x1fcc, 0x1fcc, HB_Letter_Titlecase},
+ {0x1fcd, 0x1fcf, HB_Symbol_Modifier},
+ {0x1fd0, 0x1fd3, HB_Letter_Lowercase},
+ {0x1fd4, 0x1fd5, HB_Other_NotAssigned},
+ {0x1fd6, 0x1fd7, HB_Letter_Lowercase},
+ {0x1fd8, 0x1fdb, HB_Letter_Uppercase},
+ {0x1fdc, 0x1fdc, HB_Other_NotAssigned},
+ {0x1fdd, 0x1fdf, HB_Symbol_Modifier},
+ {0x1fe0, 0x1fe7, HB_Letter_Lowercase},
+ {0x1fe8, 0x1fec, HB_Letter_Uppercase},
+ {0x1fed, 0x1fef, HB_Symbol_Modifier},
+ {0x1ff0, 0x1ff1, HB_Other_NotAssigned},
+ {0x1ff2, 0x1ff4, HB_Letter_Lowercase},
+ {0x1ff5, 0x1ff5, HB_Other_NotAssigned},
+ {0x1ff6, 0x1ff7, HB_Letter_Lowercase},
+ {0x1ff8, 0x1ffb, HB_Letter_Uppercase},
+ {0x1ffc, 0x1ffc, HB_Letter_Titlecase},
+ {0x1ffd, 0x1ffe, HB_Symbol_Modifier},
+ {0x1fff, 0x1fff, HB_Other_NotAssigned},
+ {0x2000, 0x200a, HB_Separator_Space},
+ {0x200b, 0x200f, HB_Other_Format},
+ {0x2010, 0x2015, HB_Punctuation_Dash},
+ {0x2016, 0x2017, HB_Punctuation_Other},
+ {0x2018, 0x2018, HB_Punctuation_InitialQuote},
+ {0x2019, 0x2019, HB_Punctuation_FinalQuote},
+ {0x201a, 0x201a, HB_Punctuation_Open},
+ {0x201b, 0x201c, HB_Punctuation_InitialQuote},
+ {0x201d, 0x201d, HB_Punctuation_FinalQuote},
+ {0x201e, 0x201e, HB_Punctuation_Open},
+ {0x201f, 0x201f, HB_Punctuation_InitialQuote},
+ {0x2020, 0x2027, HB_Punctuation_Other},
+ {0x2028, 0x2028, HB_Separator_Line},
+ {0x2029, 0x2029, HB_Separator_Paragraph},
+ {0x202a, 0x202e, HB_Other_Format},
+ {0x202f, 0x202f, HB_Separator_Space},
+ {0x2030, 0x2038, HB_Punctuation_Other},
+ {0x2039, 0x2039, HB_Punctuation_InitialQuote},
+ {0x203a, 0x203a, HB_Punctuation_FinalQuote},
+ {0x203b, 0x203e, HB_Punctuation_Other},
+ {0x203f, 0x2040, HB_Punctuation_Connector},
+ {0x2041, 0x2043, HB_Punctuation_Other},
+ {0x2044, 0x2044, HB_Symbol_Math},
+ {0x2045, 0x2045, HB_Punctuation_Open},
+ {0x2046, 0x2046, HB_Punctuation_Close},
+ {0x2047, 0x2051, HB_Punctuation_Other},
+ {0x2052, 0x2052, HB_Symbol_Math},
+ {0x2053, 0x2053, HB_Punctuation_Other},
+ {0x2054, 0x2054, HB_Punctuation_Connector},
+ {0x2055, 0x205e, HB_Punctuation_Other},
+ {0x205f, 0x205f, HB_Separator_Space},
+ {0x2060, 0x2064, HB_Other_Format},
+ {0x2065, 0x2069, HB_Other_NotAssigned},
+ {0x206a, 0x206f, HB_Other_Format},
+ {0x2070, 0x2070, HB_Number_Other},
+ {0x2071, 0x2071, HB_Letter_Lowercase},
+ {0x2072, 0x2073, HB_Other_NotAssigned},
+ {0x2074, 0x2079, HB_Number_Other},
+ {0x207a, 0x207c, HB_Symbol_Math},
+ {0x207d, 0x207d, HB_Punctuation_Open},
+ {0x207e, 0x207e, HB_Punctuation_Close},
+ {0x207f, 0x207f, HB_Letter_Lowercase},
+ {0x2080, 0x2089, HB_Number_Other},
+ {0x208a, 0x208c, HB_Symbol_Math},
+ {0x208d, 0x208d, HB_Punctuation_Open},
+ {0x208e, 0x208e, HB_Punctuation_Close},
+ {0x208f, 0x208f, HB_Other_NotAssigned},
+ {0x2090, 0x2094, HB_Letter_Modifier},
+ {0x2095, 0x209f, HB_Other_NotAssigned},
+ {0x20a0, 0x20b5, HB_Symbol_Currency},
+ {0x20b6, 0x20cf, HB_Other_NotAssigned},
+ {0x20d0, 0x20dc, HB_Mark_NonSpacing},
+ {0x20dd, 0x20e0, HB_Mark_Enclosing},
+ {0x20e1, 0x20e1, HB_Mark_NonSpacing},
+ {0x20e2, 0x20e4, HB_Mark_Enclosing},
+ {0x20e5, 0x20f0, HB_Mark_NonSpacing},
+ {0x20f1, 0x20ff, HB_Other_NotAssigned},
+ {0x2100, 0x2101, HB_Symbol_Other},
+ {0x2102, 0x2102, HB_Letter_Uppercase},
+ {0x2103, 0x2106, HB_Symbol_Other},
+ {0x2107, 0x2107, HB_Letter_Uppercase},
+ {0x2108, 0x2109, HB_Symbol_Other},
+ {0x210a, 0x210a, HB_Letter_Lowercase},
+ {0x210b, 0x210d, HB_Letter_Uppercase},
+ {0x210e, 0x210f, HB_Letter_Lowercase},
+ {0x2110, 0x2112, HB_Letter_Uppercase},
+ {0x2113, 0x2113, HB_Letter_Lowercase},
+ {0x2114, 0x2114, HB_Symbol_Other},
+ {0x2115, 0x2115, HB_Letter_Uppercase},
+ {0x2116, 0x2118, HB_Symbol_Other},
+ {0x2119, 0x211d, HB_Letter_Uppercase},
+ {0x211e, 0x2123, HB_Symbol_Other},
+ {0x2124, 0x2124, HB_Letter_Uppercase},
+ {0x2125, 0x2125, HB_Symbol_Other},
+ {0x2126, 0x2126, HB_Letter_Uppercase},
+ {0x2127, 0x2127, HB_Symbol_Other},
+ {0x2128, 0x2128, HB_Letter_Uppercase},
+ {0x2129, 0x2129, HB_Symbol_Other},
+ {0x212a, 0x212d, HB_Letter_Uppercase},
+ {0x212e, 0x212e, HB_Symbol_Other},
+ {0x212f, 0x212f, HB_Letter_Lowercase},
+ {0x2130, 0x2133, HB_Letter_Uppercase},
+ {0x2134, 0x2134, HB_Letter_Lowercase},
+ {0x2135, 0x2138, HB_Letter_Other},
+ {0x2139, 0x2139, HB_Letter_Lowercase},
+ {0x213a, 0x213b, HB_Symbol_Other},
+ {0x213c, 0x213d, HB_Letter_Lowercase},
+ {0x213e, 0x213f, HB_Letter_Uppercase},
+ {0x2140, 0x2144, HB_Symbol_Math},
+ {0x2145, 0x2145, HB_Letter_Uppercase},
+ {0x2146, 0x2149, HB_Letter_Lowercase},
+ {0x214a, 0x214a, HB_Symbol_Other},
+ {0x214b, 0x214b, HB_Symbol_Math},
+ {0x214c, 0x214d, HB_Symbol_Other},
+ {0x214e, 0x214e, HB_Letter_Lowercase},
+ {0x214f, 0x214f, HB_Symbol_Other},
+ {0x2150, 0x2152, HB_Other_NotAssigned},
+ {0x2153, 0x215f, HB_Number_Other},
+ {0x2160, 0x2182, HB_Number_Letter},
+ {0x2183, 0x2183, HB_Letter_Uppercase},
+ {0x2184, 0x2184, HB_Letter_Lowercase},
+ {0x2185, 0x2188, HB_Number_Letter},
+ {0x2189, 0x218f, HB_Other_NotAssigned},
+ {0x2190, 0x2194, HB_Symbol_Math},
+ {0x2195, 0x2199, HB_Symbol_Other},
+ {0x219a, 0x219b, HB_Symbol_Math},
+ {0x219c, 0x219f, HB_Symbol_Other},
+ {0x21a0, 0x21a0, HB_Symbol_Math},
+ {0x21a1, 0x21a2, HB_Symbol_Other},
+ {0x21a3, 0x21a3, HB_Symbol_Math},
+ {0x21a4, 0x21a5, HB_Symbol_Other},
+ {0x21a6, 0x21a6, HB_Symbol_Math},
+ {0x21a7, 0x21ad, HB_Symbol_Other},
+ {0x21ae, 0x21ae, HB_Symbol_Math},
+ {0x21af, 0x21cd, HB_Symbol_Other},
+ {0x21ce, 0x21cf, HB_Symbol_Math},
+ {0x21d0, 0x21d1, HB_Symbol_Other},
+ {0x21d2, 0x21d2, HB_Symbol_Math},
+ {0x21d3, 0x21d3, HB_Symbol_Other},
+ {0x21d4, 0x21d4, HB_Symbol_Math},
+ {0x21d5, 0x21f3, HB_Symbol_Other},
+ {0x21f4, 0x22ff, HB_Symbol_Math},
+ {0x2300, 0x2307, HB_Symbol_Other},
+ {0x2308, 0x230b, HB_Symbol_Math},
+ {0x230c, 0x231f, HB_Symbol_Other},
+ {0x2320, 0x2321, HB_Symbol_Math},
+ {0x2322, 0x2328, HB_Symbol_Other},
+ {0x2329, 0x2329, HB_Punctuation_Open},
+ {0x232a, 0x232a, HB_Punctuation_Close},
+ {0x232b, 0x237b, HB_Symbol_Other},
+ {0x237c, 0x237c, HB_Symbol_Math},
+ {0x237d, 0x239a, HB_Symbol_Other},
+ {0x239b, 0x23b3, HB_Symbol_Math},
+ {0x23b4, 0x23db, HB_Symbol_Other},
+ {0x23dc, 0x23e1, HB_Symbol_Math},
+ {0x23e2, 0x23e7, HB_Symbol_Other},
+ {0x23e8, 0x23ff, HB_Other_NotAssigned},
+ {0x2400, 0x2426, HB_Symbol_Other},
+ {0x2427, 0x243f, HB_Other_NotAssigned},
+ {0x2440, 0x244a, HB_Symbol_Other},
+ {0x244b, 0x245f, HB_Other_NotAssigned},
+ {0x2460, 0x249b, HB_Number_Other},
+ {0x249c, 0x24e9, HB_Symbol_Other},
+ {0x24ea, 0x24ff, HB_Number_Other},
+ {0x2500, 0x25b6, HB_Symbol_Other},
+ {0x25b7, 0x25b7, HB_Symbol_Math},
+ {0x25b8, 0x25c0, HB_Symbol_Other},
+ {0x25c1, 0x25c1, HB_Symbol_Math},
+ {0x25c2, 0x25f7, HB_Symbol_Other},
+ {0x25f8, 0x25ff, HB_Symbol_Math},
+ {0x2600, 0x266e, HB_Symbol_Other},
+ {0x266f, 0x266f, HB_Symbol_Math},
+ {0x2670, 0x269d, HB_Symbol_Other},
+ {0x269e, 0x269f, HB_Other_NotAssigned},
+ {0x26a0, 0x26bc, HB_Symbol_Other},
+ {0x26bd, 0x26bf, HB_Other_NotAssigned},
+ {0x26c0, 0x26c3, HB_Symbol_Other},
+ {0x26c4, 0x2700, HB_Other_NotAssigned},
+ {0x2701, 0x2704, HB_Symbol_Other},
+ {0x2705, 0x2705, HB_Other_NotAssigned},
+ {0x2706, 0x2709, HB_Symbol_Other},
+ {0x270a, 0x270b, HB_Other_NotAssigned},
+ {0x270c, 0x2727, HB_Symbol_Other},
+ {0x2728, 0x2728, HB_Other_NotAssigned},
+ {0x2729, 0x274b, HB_Symbol_Other},
+ {0x274c, 0x274c, HB_Other_NotAssigned},
+ {0x274d, 0x274d, HB_Symbol_Other},
+ {0x274e, 0x274e, HB_Other_NotAssigned},
+ {0x274f, 0x2752, HB_Symbol_Other},
+ {0x2753, 0x2755, HB_Other_NotAssigned},
+ {0x2756, 0x2756, HB_Symbol_Other},
+ {0x2757, 0x2757, HB_Other_NotAssigned},
+ {0x2758, 0x275e, HB_Symbol_Other},
+ {0x275f, 0x2760, HB_Other_NotAssigned},
+ {0x2761, 0x2767, HB_Symbol_Other},
+ {0x2768, 0x2768, HB_Punctuation_Open},
+ {0x2769, 0x2769, HB_Punctuation_Close},
+ {0x276a, 0x276a, HB_Punctuation_Open},
+ {0x276b, 0x276b, HB_Punctuation_Close},
+ {0x276c, 0x276c, HB_Punctuation_Open},
+ {0x276d, 0x276d, HB_Punctuation_Close},
+ {0x276e, 0x276e, HB_Punctuation_Open},
+ {0x276f, 0x276f, HB_Punctuation_Close},
+ {0x2770, 0x2770, HB_Punctuation_Open},
+ {0x2771, 0x2771, HB_Punctuation_Close},
+ {0x2772, 0x2772, HB_Punctuation_Open},
+ {0x2773, 0x2773, HB_Punctuation_Close},
+ {0x2774, 0x2774, HB_Punctuation_Open},
+ {0x2775, 0x2775, HB_Punctuation_Close},
+ {0x2776, 0x2793, HB_Number_Other},
+ {0x2794, 0x2794, HB_Symbol_Other},
+ {0x2795, 0x2797, HB_Other_NotAssigned},
+ {0x2798, 0x27af, HB_Symbol_Other},
+ {0x27b0, 0x27b0, HB_Other_NotAssigned},
+ {0x27b1, 0x27be, HB_Symbol_Other},
+ {0x27bf, 0x27bf, HB_Other_NotAssigned},
+ {0x27c0, 0x27c4, HB_Symbol_Math},
+ {0x27c5, 0x27c5, HB_Punctuation_Open},
+ {0x27c6, 0x27c6, HB_Punctuation_Close},
+ {0x27c7, 0x27ca, HB_Symbol_Math},
+ {0x27cb, 0x27cb, HB_Other_NotAssigned},
+ {0x27cc, 0x27cc, HB_Symbol_Math},
+ {0x27cd, 0x27cf, HB_Other_NotAssigned},
+ {0x27d0, 0x27e5, HB_Symbol_Math},
+ {0x27e6, 0x27e6, HB_Punctuation_Open},
+ {0x27e7, 0x27e7, HB_Punctuation_Close},
+ {0x27e8, 0x27e8, HB_Punctuation_Open},
+ {0x27e9, 0x27e9, HB_Punctuation_Close},
+ {0x27ea, 0x27ea, HB_Punctuation_Open},
+ {0x27eb, 0x27eb, HB_Punctuation_Close},
+ {0x27ec, 0x27ec, HB_Punctuation_Open},
+ {0x27ed, 0x27ed, HB_Punctuation_Close},
+ {0x27ee, 0x27ee, HB_Punctuation_Open},
+ {0x27ef, 0x27ef, HB_Punctuation_Close},
+ {0x27f0, 0x27ff, HB_Symbol_Math},
+ {0x2800, 0x28ff, HB_Symbol_Other},
+ {0x2900, 0x2982, HB_Symbol_Math},
+ {0x2983, 0x2983, HB_Punctuation_Open},
+ {0x2984, 0x2984, HB_Punctuation_Close},
+ {0x2985, 0x2985, HB_Punctuation_Open},
+ {0x2986, 0x2986, HB_Punctuation_Close},
+ {0x2987, 0x2987, HB_Punctuation_Open},
+ {0x2988, 0x2988, HB_Punctuation_Close},
+ {0x2989, 0x2989, HB_Punctuation_Open},
+ {0x298a, 0x298a, HB_Punctuation_Close},
+ {0x298b, 0x298b, HB_Punctuation_Open},
+ {0x298c, 0x298c, HB_Punctuation_Close},
+ {0x298d, 0x298d, HB_Punctuation_Open},
+ {0x298e, 0x298e, HB_Punctuation_Close},
+ {0x298f, 0x298f, HB_Punctuation_Open},
+ {0x2990, 0x2990, HB_Punctuation_Close},
+ {0x2991, 0x2991, HB_Punctuation_Open},
+ {0x2992, 0x2992, HB_Punctuation_Close},
+ {0x2993, 0x2993, HB_Punctuation_Open},
+ {0x2994, 0x2994, HB_Punctuation_Close},
+ {0x2995, 0x2995, HB_Punctuation_Open},
+ {0x2996, 0x2996, HB_Punctuation_Close},
+ {0x2997, 0x2997, HB_Punctuation_Open},
+ {0x2998, 0x2998, HB_Punctuation_Close},
+ {0x2999, 0x29d7, HB_Symbol_Math},
+ {0x29d8, 0x29d8, HB_Punctuation_Open},
+ {0x29d9, 0x29d9, HB_Punctuation_Close},
+ {0x29da, 0x29da, HB_Punctuation_Open},
+ {0x29db, 0x29db, HB_Punctuation_Close},
+ {0x29dc, 0x29fb, HB_Symbol_Math},
+ {0x29fc, 0x29fc, HB_Punctuation_Open},
+ {0x29fd, 0x29fd, HB_Punctuation_Close},
+ {0x29fe, 0x2aff, HB_Symbol_Math},
+ {0x2b00, 0x2b2f, HB_Symbol_Other},
+ {0x2b30, 0x2b44, HB_Symbol_Math},
+ {0x2b45, 0x2b46, HB_Symbol_Other},
+ {0x2b47, 0x2b4c, HB_Symbol_Math},
+ {0x2b4d, 0x2b4f, HB_Other_NotAssigned},
+ {0x2b50, 0x2b54, HB_Symbol_Other},
+ {0x2b55, 0x2bff, HB_Other_NotAssigned},
+ {0x2c00, 0x2c2e, HB_Letter_Uppercase},
+ {0x2c2f, 0x2c2f, HB_Other_NotAssigned},
+ {0x2c30, 0x2c5e, HB_Letter_Lowercase},
+ {0x2c5f, 0x2c5f, HB_Other_NotAssigned},
+ {0x2c60, 0x2c60, HB_Letter_Uppercase},
+ {0x2c61, 0x2c61, HB_Letter_Lowercase},
+ {0x2c62, 0x2c64, HB_Letter_Uppercase},
+ {0x2c65, 0x2c66, HB_Letter_Lowercase},
+ {0x2c67, 0x2c67, HB_Letter_Uppercase},
+ {0x2c68, 0x2c68, HB_Letter_Lowercase},
+ {0x2c69, 0x2c69, HB_Letter_Uppercase},
+ {0x2c6a, 0x2c6a, HB_Letter_Lowercase},
+ {0x2c6b, 0x2c6b, HB_Letter_Uppercase},
+ {0x2c6c, 0x2c6c, HB_Letter_Lowercase},
+ {0x2c6d, 0x2c6f, HB_Letter_Uppercase},
+ {0x2c70, 0x2c70, HB_Other_NotAssigned},
+ {0x2c71, 0x2c71, HB_Letter_Lowercase},
+ {0x2c72, 0x2c72, HB_Letter_Uppercase},
+ {0x2c73, 0x2c74, HB_Letter_Lowercase},
+ {0x2c75, 0x2c75, HB_Letter_Uppercase},
+ {0x2c76, 0x2c7c, HB_Letter_Lowercase},
+ {0x2c7d, 0x2c7d, HB_Letter_Modifier},
+ {0x2c7e, 0x2c7f, HB_Other_NotAssigned},
+ {0x2c80, 0x2c80, HB_Letter_Uppercase},
+ {0x2c81, 0x2c81, HB_Letter_Lowercase},
+ {0x2c82, 0x2c82, HB_Letter_Uppercase},
+ {0x2c83, 0x2c83, HB_Letter_Lowercase},
+ {0x2c84, 0x2c84, HB_Letter_Uppercase},
+ {0x2c85, 0x2c85, HB_Letter_Lowercase},
+ {0x2c86, 0x2c86, HB_Letter_Uppercase},
+ {0x2c87, 0x2c87, HB_Letter_Lowercase},
+ {0x2c88, 0x2c88, HB_Letter_Uppercase},
+ {0x2c89, 0x2c89, HB_Letter_Lowercase},
+ {0x2c8a, 0x2c8a, HB_Letter_Uppercase},
+ {0x2c8b, 0x2c8b, HB_Letter_Lowercase},
+ {0x2c8c, 0x2c8c, HB_Letter_Uppercase},
+ {0x2c8d, 0x2c8d, HB_Letter_Lowercase},
+ {0x2c8e, 0x2c8e, HB_Letter_Uppercase},
+ {0x2c8f, 0x2c8f, HB_Letter_Lowercase},
+ {0x2c90, 0x2c90, HB_Letter_Uppercase},
+ {0x2c91, 0x2c91, HB_Letter_Lowercase},
+ {0x2c92, 0x2c92, HB_Letter_Uppercase},
+ {0x2c93, 0x2c93, HB_Letter_Lowercase},
+ {0x2c94, 0x2c94, HB_Letter_Uppercase},
+ {0x2c95, 0x2c95, HB_Letter_Lowercase},
+ {0x2c96, 0x2c96, HB_Letter_Uppercase},
+ {0x2c97, 0x2c97, HB_Letter_Lowercase},
+ {0x2c98, 0x2c98, HB_Letter_Uppercase},
+ {0x2c99, 0x2c99, HB_Letter_Lowercase},
+ {0x2c9a, 0x2c9a, HB_Letter_Uppercase},
+ {0x2c9b, 0x2c9b, HB_Letter_Lowercase},
+ {0x2c9c, 0x2c9c, HB_Letter_Uppercase},
+ {0x2c9d, 0x2c9d, HB_Letter_Lowercase},
+ {0x2c9e, 0x2c9e, HB_Letter_Uppercase},
+ {0x2c9f, 0x2c9f, HB_Letter_Lowercase},
+ {0x2ca0, 0x2ca0, HB_Letter_Uppercase},
+ {0x2ca1, 0x2ca1, HB_Letter_Lowercase},
+ {0x2ca2, 0x2ca2, HB_Letter_Uppercase},
+ {0x2ca3, 0x2ca3, HB_Letter_Lowercase},
+ {0x2ca4, 0x2ca4, HB_Letter_Uppercase},
+ {0x2ca5, 0x2ca5, HB_Letter_Lowercase},
+ {0x2ca6, 0x2ca6, HB_Letter_Uppercase},
+ {0x2ca7, 0x2ca7, HB_Letter_Lowercase},
+ {0x2ca8, 0x2ca8, HB_Letter_Uppercase},
+ {0x2ca9, 0x2ca9, HB_Letter_Lowercase},
+ {0x2caa, 0x2caa, HB_Letter_Uppercase},
+ {0x2cab, 0x2cab, HB_Letter_Lowercase},
+ {0x2cac, 0x2cac, HB_Letter_Uppercase},
+ {0x2cad, 0x2cad, HB_Letter_Lowercase},
+ {0x2cae, 0x2cae, HB_Letter_Uppercase},
+ {0x2caf, 0x2caf, HB_Letter_Lowercase},
+ {0x2cb0, 0x2cb0, HB_Letter_Uppercase},
+ {0x2cb1, 0x2cb1, HB_Letter_Lowercase},
+ {0x2cb2, 0x2cb2, HB_Letter_Uppercase},
+ {0x2cb3, 0x2cb3, HB_Letter_Lowercase},
+ {0x2cb4, 0x2cb4, HB_Letter_Uppercase},
+ {0x2cb5, 0x2cb5, HB_Letter_Lowercase},
+ {0x2cb6, 0x2cb6, HB_Letter_Uppercase},
+ {0x2cb7, 0x2cb7, HB_Letter_Lowercase},
+ {0x2cb8, 0x2cb8, HB_Letter_Uppercase},
+ {0x2cb9, 0x2cb9, HB_Letter_Lowercase},
+ {0x2cba, 0x2cba, HB_Letter_Uppercase},
+ {0x2cbb, 0x2cbb, HB_Letter_Lowercase},
+ {0x2cbc, 0x2cbc, HB_Letter_Uppercase},
+ {0x2cbd, 0x2cbd, HB_Letter_Lowercase},
+ {0x2cbe, 0x2cbe, HB_Letter_Uppercase},
+ {0x2cbf, 0x2cbf, HB_Letter_Lowercase},
+ {0x2cc0, 0x2cc0, HB_Letter_Uppercase},
+ {0x2cc1, 0x2cc1, HB_Letter_Lowercase},
+ {0x2cc2, 0x2cc2, HB_Letter_Uppercase},
+ {0x2cc3, 0x2cc3, HB_Letter_Lowercase},
+ {0x2cc4, 0x2cc4, HB_Letter_Uppercase},
+ {0x2cc5, 0x2cc5, HB_Letter_Lowercase},
+ {0x2cc6, 0x2cc6, HB_Letter_Uppercase},
+ {0x2cc7, 0x2cc7, HB_Letter_Lowercase},
+ {0x2cc8, 0x2cc8, HB_Letter_Uppercase},
+ {0x2cc9, 0x2cc9, HB_Letter_Lowercase},
+ {0x2cca, 0x2cca, HB_Letter_Uppercase},
+ {0x2ccb, 0x2ccb, HB_Letter_Lowercase},
+ {0x2ccc, 0x2ccc, HB_Letter_Uppercase},
+ {0x2ccd, 0x2ccd, HB_Letter_Lowercase},
+ {0x2cce, 0x2cce, HB_Letter_Uppercase},
+ {0x2ccf, 0x2ccf, HB_Letter_Lowercase},
+ {0x2cd0, 0x2cd0, HB_Letter_Uppercase},
+ {0x2cd1, 0x2cd1, HB_Letter_Lowercase},
+ {0x2cd2, 0x2cd2, HB_Letter_Uppercase},
+ {0x2cd3, 0x2cd3, HB_Letter_Lowercase},
+ {0x2cd4, 0x2cd4, HB_Letter_Uppercase},
+ {0x2cd5, 0x2cd5, HB_Letter_Lowercase},
+ {0x2cd6, 0x2cd6, HB_Letter_Uppercase},
+ {0x2cd7, 0x2cd7, HB_Letter_Lowercase},
+ {0x2cd8, 0x2cd8, HB_Letter_Uppercase},
+ {0x2cd9, 0x2cd9, HB_Letter_Lowercase},
+ {0x2cda, 0x2cda, HB_Letter_Uppercase},
+ {0x2cdb, 0x2cdb, HB_Letter_Lowercase},
+ {0x2cdc, 0x2cdc, HB_Letter_Uppercase},
+ {0x2cdd, 0x2cdd, HB_Letter_Lowercase},
+ {0x2cde, 0x2cde, HB_Letter_Uppercase},
+ {0x2cdf, 0x2cdf, HB_Letter_Lowercase},
+ {0x2ce0, 0x2ce0, HB_Letter_Uppercase},
+ {0x2ce1, 0x2ce1, HB_Letter_Lowercase},
+ {0x2ce2, 0x2ce2, HB_Letter_Uppercase},
+ {0x2ce3, 0x2ce4, HB_Letter_Lowercase},
+ {0x2ce5, 0x2cea, HB_Symbol_Other},
+ {0x2ceb, 0x2cf8, HB_Other_NotAssigned},
+ {0x2cf9, 0x2cfc, HB_Punctuation_Other},
+ {0x2cfd, 0x2cfd, HB_Number_Other},
+ {0x2cfe, 0x2cff, HB_Punctuation_Other},
+ {0x2d00, 0x2d25, HB_Letter_Lowercase},
+ {0x2d26, 0x2d2f, HB_Other_NotAssigned},
+ {0x2d30, 0x2d65, HB_Letter_Other},
+ {0x2d66, 0x2d6e, HB_Other_NotAssigned},
+ {0x2d6f, 0x2d6f, HB_Letter_Modifier},
+ {0x2d70, 0x2d7f, HB_Other_NotAssigned},
+ {0x2d80, 0x2d96, HB_Letter_Other},
+ {0x2d97, 0x2d9f, HB_Other_NotAssigned},
+ {0x2da0, 0x2da6, HB_Letter_Other},
+ {0x2da7, 0x2da7, HB_Other_NotAssigned},
+ {0x2da8, 0x2dae, HB_Letter_Other},
+ {0x2daf, 0x2daf, HB_Other_NotAssigned},
+ {0x2db0, 0x2db6, HB_Letter_Other},
+ {0x2db7, 0x2db7, HB_Other_NotAssigned},
+ {0x2db8, 0x2dbe, HB_Letter_Other},
+ {0x2dbf, 0x2dbf, HB_Other_NotAssigned},
+ {0x2dc0, 0x2dc6, HB_Letter_Other},
+ {0x2dc7, 0x2dc7, HB_Other_NotAssigned},
+ {0x2dc8, 0x2dce, HB_Letter_Other},
+ {0x2dcf, 0x2dcf, HB_Other_NotAssigned},
+ {0x2dd0, 0x2dd6, HB_Letter_Other},
+ {0x2dd7, 0x2dd7, HB_Other_NotAssigned},
+ {0x2dd8, 0x2dde, HB_Letter_Other},
+ {0x2ddf, 0x2ddf, HB_Other_NotAssigned},
+ {0x2de0, 0x2dff, HB_Mark_NonSpacing},
+ {0x2e00, 0x2e01, HB_Punctuation_Other},
+ {0x2e02, 0x2e02, HB_Punctuation_InitialQuote},
+ {0x2e03, 0x2e03, HB_Punctuation_FinalQuote},
+ {0x2e04, 0x2e04, HB_Punctuation_InitialQuote},
+ {0x2e05, 0x2e05, HB_Punctuation_FinalQuote},
+ {0x2e06, 0x2e08, HB_Punctuation_Other},
+ {0x2e09, 0x2e09, HB_Punctuation_InitialQuote},
+ {0x2e0a, 0x2e0a, HB_Punctuation_FinalQuote},
+ {0x2e0b, 0x2e0b, HB_Punctuation_Other},
+ {0x2e0c, 0x2e0c, HB_Punctuation_InitialQuote},
+ {0x2e0d, 0x2e0d, HB_Punctuation_FinalQuote},
+ {0x2e0e, 0x2e16, HB_Punctuation_Other},
+ {0x2e17, 0x2e17, HB_Punctuation_Dash},
+ {0x2e18, 0x2e19, HB_Punctuation_Other},
+ {0x2e1a, 0x2e1a, HB_Punctuation_Dash},
+ {0x2e1b, 0x2e1b, HB_Punctuation_Other},
+ {0x2e1c, 0x2e1c, HB_Punctuation_InitialQuote},
+ {0x2e1d, 0x2e1d, HB_Punctuation_FinalQuote},
+ {0x2e1e, 0x2e1f, HB_Punctuation_Other},
+ {0x2e20, 0x2e20, HB_Punctuation_InitialQuote},
+ {0x2e21, 0x2e21, HB_Punctuation_FinalQuote},
+ {0x2e22, 0x2e22, HB_Punctuation_Open},
+ {0x2e23, 0x2e23, HB_Punctuation_Close},
+ {0x2e24, 0x2e24, HB_Punctuation_Open},
+ {0x2e25, 0x2e25, HB_Punctuation_Close},
+ {0x2e26, 0x2e26, HB_Punctuation_Open},
+ {0x2e27, 0x2e27, HB_Punctuation_Close},
+ {0x2e28, 0x2e28, HB_Punctuation_Open},
+ {0x2e29, 0x2e29, HB_Punctuation_Close},
+ {0x2e2a, 0x2e2e, HB_Punctuation_Other},
+ {0x2e2f, 0x2e2f, HB_Letter_Modifier},
+ {0x2e30, 0x2e30, HB_Punctuation_Other},
+ {0x2e31, 0x2e7f, HB_Other_NotAssigned},
+ {0x2e80, 0x2e99, HB_Symbol_Other},
+ {0x2e9a, 0x2e9a, HB_Other_NotAssigned},
+ {0x2e9b, 0x2ef3, HB_Symbol_Other},
+ {0x2ef4, 0x2eff, HB_Other_NotAssigned},
+ {0x2f00, 0x2fd5, HB_Symbol_Other},
+ {0x2fd6, 0x2fef, HB_Other_NotAssigned},
+ {0x2ff0, 0x2ffb, HB_Symbol_Other},
+ {0x2ffc, 0x2fff, HB_Other_NotAssigned},
+ {0x3000, 0x3000, HB_Separator_Space},
+ {0x3001, 0x3003, HB_Punctuation_Other},
+ {0x3004, 0x3004, HB_Symbol_Other},
+ {0x3005, 0x3005, HB_Letter_Modifier},
+ {0x3006, 0x3006, HB_Letter_Other},
+ {0x3007, 0x3007, HB_Number_Letter},
+ {0x3008, 0x3008, HB_Punctuation_Open},
+ {0x3009, 0x3009, HB_Punctuation_Close},
+ {0x300a, 0x300a, HB_Punctuation_Open},
+ {0x300b, 0x300b, HB_Punctuation_Close},
+ {0x300c, 0x300c, HB_Punctuation_Open},
+ {0x300d, 0x300d, HB_Punctuation_Close},
+ {0x300e, 0x300e, HB_Punctuation_Open},
+ {0x300f, 0x300f, HB_Punctuation_Close},
+ {0x3010, 0x3010, HB_Punctuation_Open},
+ {0x3011, 0x3011, HB_Punctuation_Close},
+ {0x3012, 0x3013, HB_Symbol_Other},
+ {0x3014, 0x3014, HB_Punctuation_Open},
+ {0x3015, 0x3015, HB_Punctuation_Close},
+ {0x3016, 0x3016, HB_Punctuation_Open},
+ {0x3017, 0x3017, HB_Punctuation_Close},
+ {0x3018, 0x3018, HB_Punctuation_Open},
+ {0x3019, 0x3019, HB_Punctuation_Close},
+ {0x301a, 0x301a, HB_Punctuation_Open},
+ {0x301b, 0x301b, HB_Punctuation_Close},
+ {0x301c, 0x301c, HB_Punctuation_Dash},
+ {0x301d, 0x301d, HB_Punctuation_Open},
+ {0x301e, 0x301f, HB_Punctuation_Close},
+ {0x3020, 0x3020, HB_Symbol_Other},
+ {0x3021, 0x3029, HB_Number_Letter},
+ {0x302a, 0x302f, HB_Mark_NonSpacing},
+ {0x3030, 0x3030, HB_Punctuation_Dash},
+ {0x3031, 0x3035, HB_Letter_Modifier},
+ {0x3036, 0x3037, HB_Symbol_Other},
+ {0x3038, 0x303a, HB_Number_Letter},
+ {0x303b, 0x303b, HB_Letter_Modifier},
+ {0x303c, 0x303c, HB_Letter_Other},
+ {0x303d, 0x303d, HB_Punctuation_Other},
+ {0x303e, 0x303f, HB_Symbol_Other},
+ {0x3040, 0x3040, HB_Other_NotAssigned},
+ {0x3041, 0x3096, HB_Letter_Other},
+ {0x3097, 0x3098, HB_Other_NotAssigned},
+ {0x3099, 0x309a, HB_Mark_NonSpacing},
+ {0x309b, 0x309c, HB_Symbol_Modifier},
+ {0x309d, 0x309e, HB_Letter_Modifier},
+ {0x309f, 0x309f, HB_Letter_Other},
+ {0x30a0, 0x30a0, HB_Punctuation_Dash},
+ {0x30a1, 0x30fa, HB_Letter_Other},
+ {0x30fb, 0x30fb, HB_Punctuation_Other},
+ {0x30fc, 0x30fe, HB_Letter_Modifier},
+ {0x30ff, 0x30ff, HB_Letter_Other},
+ {0x3100, 0x3104, HB_Other_NotAssigned},
+ {0x3105, 0x312d, HB_Letter_Other},
+ {0x312e, 0x3130, HB_Other_NotAssigned},
+ {0x3131, 0x318e, HB_Letter_Other},
+ {0x318f, 0x318f, HB_Other_NotAssigned},
+ {0x3190, 0x3191, HB_Symbol_Other},
+ {0x3192, 0x3195, HB_Number_Other},
+ {0x3196, 0x319f, HB_Symbol_Other},
+ {0x31a0, 0x31b7, HB_Letter_Other},
+ {0x31b8, 0x31bf, HB_Other_NotAssigned},
+ {0x31c0, 0x31e3, HB_Symbol_Other},
+ {0x31e4, 0x31ef, HB_Other_NotAssigned},
+ {0x31f0, 0x31ff, HB_Letter_Other},
+ {0x3200, 0x321e, HB_Symbol_Other},
+ {0x321f, 0x321f, HB_Other_NotAssigned},
+ {0x3220, 0x3229, HB_Number_Other},
+ {0x322a, 0x3243, HB_Symbol_Other},
+ {0x3244, 0x324f, HB_Other_NotAssigned},
+ {0x3250, 0x3250, HB_Symbol_Other},
+ {0x3251, 0x325f, HB_Number_Other},
+ {0x3260, 0x327f, HB_Symbol_Other},
+ {0x3280, 0x3289, HB_Number_Other},
+ {0x328a, 0x32b0, HB_Symbol_Other},
+ {0x32b1, 0x32bf, HB_Number_Other},
+ {0x32c0, 0x32fe, HB_Symbol_Other},
+ {0x32ff, 0x32ff, HB_Other_NotAssigned},
+ {0x3300, 0x33ff, HB_Symbol_Other},
+ {0x3400, 0x4db5, HB_Letter_Other},
+ {0x4db6, 0x4dbf, HB_Other_NotAssigned},
+ {0x4dc0, 0x4dff, HB_Symbol_Other},
+ {0x4e00, 0x9fc3, HB_Letter_Other},
+ {0x9fc4, 0x9fff, HB_Other_NotAssigned},
+ {0xa000, 0xa014, HB_Letter_Other},
+ {0xa015, 0xa015, HB_Letter_Modifier},
+ {0xa016, 0xa48c, HB_Letter_Other},
+ {0xa48d, 0xa48f, HB_Other_NotAssigned},
+ {0xa490, 0xa4c6, HB_Symbol_Other},
+ {0xa4c7, 0xa4ff, HB_Other_NotAssigned},
+ {0xa500, 0xa60b, HB_Letter_Other},
+ {0xa60c, 0xa60c, HB_Letter_Modifier},
+ {0xa60d, 0xa60f, HB_Punctuation_Other},
+ {0xa610, 0xa61f, HB_Letter_Other},
+ {0xa620, 0xa629, HB_Number_DecimalDigit},
+ {0xa62a, 0xa62b, HB_Letter_Other},
+ {0xa62c, 0xa63f, HB_Other_NotAssigned},
+ {0xa640, 0xa640, HB_Letter_Uppercase},
+ {0xa641, 0xa641, HB_Letter_Lowercase},
+ {0xa642, 0xa642, HB_Letter_Uppercase},
+ {0xa643, 0xa643, HB_Letter_Lowercase},
+ {0xa644, 0xa644, HB_Letter_Uppercase},
+ {0xa645, 0xa645, HB_Letter_Lowercase},
+ {0xa646, 0xa646, HB_Letter_Uppercase},
+ {0xa647, 0xa647, HB_Letter_Lowercase},
+ {0xa648, 0xa648, HB_Letter_Uppercase},
+ {0xa649, 0xa649, HB_Letter_Lowercase},
+ {0xa64a, 0xa64a, HB_Letter_Uppercase},
+ {0xa64b, 0xa64b, HB_Letter_Lowercase},
+ {0xa64c, 0xa64c, HB_Letter_Uppercase},
+ {0xa64d, 0xa64d, HB_Letter_Lowercase},
+ {0xa64e, 0xa64e, HB_Letter_Uppercase},
+ {0xa64f, 0xa64f, HB_Letter_Lowercase},
+ {0xa650, 0xa650, HB_Letter_Uppercase},
+ {0xa651, 0xa651, HB_Letter_Lowercase},
+ {0xa652, 0xa652, HB_Letter_Uppercase},
+ {0xa653, 0xa653, HB_Letter_Lowercase},
+ {0xa654, 0xa654, HB_Letter_Uppercase},
+ {0xa655, 0xa655, HB_Letter_Lowercase},
+ {0xa656, 0xa656, HB_Letter_Uppercase},
+ {0xa657, 0xa657, HB_Letter_Lowercase},
+ {0xa658, 0xa658, HB_Letter_Uppercase},
+ {0xa659, 0xa659, HB_Letter_Lowercase},
+ {0xa65a, 0xa65a, HB_Letter_Uppercase},
+ {0xa65b, 0xa65b, HB_Letter_Lowercase},
+ {0xa65c, 0xa65c, HB_Letter_Uppercase},
+ {0xa65d, 0xa65d, HB_Letter_Lowercase},
+ {0xa65e, 0xa65e, HB_Letter_Uppercase},
+ {0xa65f, 0xa65f, HB_Letter_Lowercase},
+ {0xa660, 0xa661, HB_Other_NotAssigned},
+ {0xa662, 0xa662, HB_Letter_Uppercase},
+ {0xa663, 0xa663, HB_Letter_Lowercase},
+ {0xa664, 0xa664, HB_Letter_Uppercase},
+ {0xa665, 0xa665, HB_Letter_Lowercase},
+ {0xa666, 0xa666, HB_Letter_Uppercase},
+ {0xa667, 0xa667, HB_Letter_Lowercase},
+ {0xa668, 0xa668, HB_Letter_Uppercase},
+ {0xa669, 0xa669, HB_Letter_Lowercase},
+ {0xa66a, 0xa66a, HB_Letter_Uppercase},
+ {0xa66b, 0xa66b, HB_Letter_Lowercase},
+ {0xa66c, 0xa66c, HB_Letter_Uppercase},
+ {0xa66d, 0xa66d, HB_Letter_Lowercase},
+ {0xa66e, 0xa66e, HB_Letter_Other},
+ {0xa66f, 0xa66f, HB_Mark_NonSpacing},
+ {0xa670, 0xa672, HB_Mark_Enclosing},
+ {0xa673, 0xa673, HB_Punctuation_Other},
+ {0xa674, 0xa67b, HB_Other_NotAssigned},
+ {0xa67c, 0xa67d, HB_Mark_NonSpacing},
+ {0xa67e, 0xa67e, HB_Punctuation_Other},
+ {0xa67f, 0xa67f, HB_Letter_Modifier},
+ {0xa680, 0xa680, HB_Letter_Uppercase},
+ {0xa681, 0xa681, HB_Letter_Lowercase},
+ {0xa682, 0xa682, HB_Letter_Uppercase},
+ {0xa683, 0xa683, HB_Letter_Lowercase},
+ {0xa684, 0xa684, HB_Letter_Uppercase},
+ {0xa685, 0xa685, HB_Letter_Lowercase},
+ {0xa686, 0xa686, HB_Letter_Uppercase},
+ {0xa687, 0xa687, HB_Letter_Lowercase},
+ {0xa688, 0xa688, HB_Letter_Uppercase},
+ {0xa689, 0xa689, HB_Letter_Lowercase},
+ {0xa68a, 0xa68a, HB_Letter_Uppercase},
+ {0xa68b, 0xa68b, HB_Letter_Lowercase},
+ {0xa68c, 0xa68c, HB_Letter_Uppercase},
+ {0xa68d, 0xa68d, HB_Letter_Lowercase},
+ {0xa68e, 0xa68e, HB_Letter_Uppercase},
+ {0xa68f, 0xa68f, HB_Letter_Lowercase},
+ {0xa690, 0xa690, HB_Letter_Uppercase},
+ {0xa691, 0xa691, HB_Letter_Lowercase},
+ {0xa692, 0xa692, HB_Letter_Uppercase},
+ {0xa693, 0xa693, HB_Letter_Lowercase},
+ {0xa694, 0xa694, HB_Letter_Uppercase},
+ {0xa695, 0xa695, HB_Letter_Lowercase},
+ {0xa696, 0xa696, HB_Letter_Uppercase},
+ {0xa697, 0xa697, HB_Letter_Lowercase},
+ {0xa698, 0xa6ff, HB_Other_NotAssigned},
+ {0xa700, 0xa716, HB_Symbol_Modifier},
+ {0xa717, 0xa71f, HB_Letter_Modifier},
+ {0xa720, 0xa721, HB_Symbol_Modifier},
+ {0xa722, 0xa722, HB_Letter_Uppercase},
+ {0xa723, 0xa723, HB_Letter_Lowercase},
+ {0xa724, 0xa724, HB_Letter_Uppercase},
+ {0xa725, 0xa725, HB_Letter_Lowercase},
+ {0xa726, 0xa726, HB_Letter_Uppercase},
+ {0xa727, 0xa727, HB_Letter_Lowercase},
+ {0xa728, 0xa728, HB_Letter_Uppercase},
+ {0xa729, 0xa729, HB_Letter_Lowercase},
+ {0xa72a, 0xa72a, HB_Letter_Uppercase},
+ {0xa72b, 0xa72b, HB_Letter_Lowercase},
+ {0xa72c, 0xa72c, HB_Letter_Uppercase},
+ {0xa72d, 0xa72d, HB_Letter_Lowercase},
+ {0xa72e, 0xa72e, HB_Letter_Uppercase},
+ {0xa72f, 0xa731, HB_Letter_Lowercase},
+ {0xa732, 0xa732, HB_Letter_Uppercase},
+ {0xa733, 0xa733, HB_Letter_Lowercase},
+ {0xa734, 0xa734, HB_Letter_Uppercase},
+ {0xa735, 0xa735, HB_Letter_Lowercase},
+ {0xa736, 0xa736, HB_Letter_Uppercase},
+ {0xa737, 0xa737, HB_Letter_Lowercase},
+ {0xa738, 0xa738, HB_Letter_Uppercase},
+ {0xa739, 0xa739, HB_Letter_Lowercase},
+ {0xa73a, 0xa73a, HB_Letter_Uppercase},
+ {0xa73b, 0xa73b, HB_Letter_Lowercase},
+ {0xa73c, 0xa73c, HB_Letter_Uppercase},
+ {0xa73d, 0xa73d, HB_Letter_Lowercase},
+ {0xa73e, 0xa73e, HB_Letter_Uppercase},
+ {0xa73f, 0xa73f, HB_Letter_Lowercase},
+ {0xa740, 0xa740, HB_Letter_Uppercase},
+ {0xa741, 0xa741, HB_Letter_Lowercase},
+ {0xa742, 0xa742, HB_Letter_Uppercase},
+ {0xa743, 0xa743, HB_Letter_Lowercase},
+ {0xa744, 0xa744, HB_Letter_Uppercase},
+ {0xa745, 0xa745, HB_Letter_Lowercase},
+ {0xa746, 0xa746, HB_Letter_Uppercase},
+ {0xa747, 0xa747, HB_Letter_Lowercase},
+ {0xa748, 0xa748, HB_Letter_Uppercase},
+ {0xa749, 0xa749, HB_Letter_Lowercase},
+ {0xa74a, 0xa74a, HB_Letter_Uppercase},
+ {0xa74b, 0xa74b, HB_Letter_Lowercase},
+ {0xa74c, 0xa74c, HB_Letter_Uppercase},
+ {0xa74d, 0xa74d, HB_Letter_Lowercase},
+ {0xa74e, 0xa74e, HB_Letter_Uppercase},
+ {0xa74f, 0xa74f, HB_Letter_Lowercase},
+ {0xa750, 0xa750, HB_Letter_Uppercase},
+ {0xa751, 0xa751, HB_Letter_Lowercase},
+ {0xa752, 0xa752, HB_Letter_Uppercase},
+ {0xa753, 0xa753, HB_Letter_Lowercase},
+ {0xa754, 0xa754, HB_Letter_Uppercase},
+ {0xa755, 0xa755, HB_Letter_Lowercase},
+ {0xa756, 0xa756, HB_Letter_Uppercase},
+ {0xa757, 0xa757, HB_Letter_Lowercase},
+ {0xa758, 0xa758, HB_Letter_Uppercase},
+ {0xa759, 0xa759, HB_Letter_Lowercase},
+ {0xa75a, 0xa75a, HB_Letter_Uppercase},
+ {0xa75b, 0xa75b, HB_Letter_Lowercase},
+ {0xa75c, 0xa75c, HB_Letter_Uppercase},
+ {0xa75d, 0xa75d, HB_Letter_Lowercase},
+ {0xa75e, 0xa75e, HB_Letter_Uppercase},
+ {0xa75f, 0xa75f, HB_Letter_Lowercase},
+ {0xa760, 0xa760, HB_Letter_Uppercase},
+ {0xa761, 0xa761, HB_Letter_Lowercase},
+ {0xa762, 0xa762, HB_Letter_Uppercase},
+ {0xa763, 0xa763, HB_Letter_Lowercase},
+ {0xa764, 0xa764, HB_Letter_Uppercase},
+ {0xa765, 0xa765, HB_Letter_Lowercase},
+ {0xa766, 0xa766, HB_Letter_Uppercase},
+ {0xa767, 0xa767, HB_Letter_Lowercase},
+ {0xa768, 0xa768, HB_Letter_Uppercase},
+ {0xa769, 0xa769, HB_Letter_Lowercase},
+ {0xa76a, 0xa76a, HB_Letter_Uppercase},
+ {0xa76b, 0xa76b, HB_Letter_Lowercase},
+ {0xa76c, 0xa76c, HB_Letter_Uppercase},
+ {0xa76d, 0xa76d, HB_Letter_Lowercase},
+ {0xa76e, 0xa76e, HB_Letter_Uppercase},
+ {0xa76f, 0xa76f, HB_Letter_Lowercase},
+ {0xa770, 0xa770, HB_Letter_Modifier},
+ {0xa771, 0xa778, HB_Letter_Lowercase},
+ {0xa779, 0xa779, HB_Letter_Uppercase},
+ {0xa77a, 0xa77a, HB_Letter_Lowercase},
+ {0xa77b, 0xa77b, HB_Letter_Uppercase},
+ {0xa77c, 0xa77c, HB_Letter_Lowercase},
+ {0xa77d, 0xa77e, HB_Letter_Uppercase},
+ {0xa77f, 0xa77f, HB_Letter_Lowercase},
+ {0xa780, 0xa780, HB_Letter_Uppercase},
+ {0xa781, 0xa781, HB_Letter_Lowercase},
+ {0xa782, 0xa782, HB_Letter_Uppercase},
+ {0xa783, 0xa783, HB_Letter_Lowercase},
+ {0xa784, 0xa784, HB_Letter_Uppercase},
+ {0xa785, 0xa785, HB_Letter_Lowercase},
+ {0xa786, 0xa786, HB_Letter_Uppercase},
+ {0xa787, 0xa787, HB_Letter_Lowercase},
+ {0xa788, 0xa788, HB_Letter_Modifier},
+ {0xa789, 0xa78a, HB_Symbol_Modifier},
+ {0xa78b, 0xa78b, HB_Letter_Uppercase},
+ {0xa78c, 0xa78c, HB_Letter_Lowercase},
+ {0xa78d, 0xa7fa, HB_Other_NotAssigned},
+ {0xa7fb, 0xa801, HB_Letter_Other},
+ {0xa802, 0xa802, HB_Mark_NonSpacing},
+ {0xa803, 0xa805, HB_Letter_Other},
+ {0xa806, 0xa806, HB_Mark_NonSpacing},
+ {0xa807, 0xa80a, HB_Letter_Other},
+ {0xa80b, 0xa80b, HB_Mark_NonSpacing},
+ {0xa80c, 0xa822, HB_Letter_Other},
+ {0xa823, 0xa824, HB_Mark_SpacingCombining},
+ {0xa825, 0xa826, HB_Mark_NonSpacing},
+ {0xa827, 0xa827, HB_Mark_SpacingCombining},
+ {0xa828, 0xa82b, HB_Symbol_Other},
+ {0xa82c, 0xa83f, HB_Other_NotAssigned},
+ {0xa840, 0xa873, HB_Letter_Other},
+ {0xa874, 0xa877, HB_Punctuation_Other},
+ {0xa878, 0xa87f, HB_Other_NotAssigned},
+ {0xa880, 0xa881, HB_Mark_SpacingCombining},
+ {0xa882, 0xa8b3, HB_Letter_Other},
+ {0xa8b4, 0xa8c3, HB_Mark_SpacingCombining},
+ {0xa8c4, 0xa8c4, HB_Mark_NonSpacing},
+ {0xa8c5, 0xa8cd, HB_Other_NotAssigned},
+ {0xa8ce, 0xa8cf, HB_Punctuation_Other},
+ {0xa8d0, 0xa8d9, HB_Number_DecimalDigit},
+ {0xa8da, 0xa8ff, HB_Other_NotAssigned},
+ {0xa900, 0xa909, HB_Number_DecimalDigit},
+ {0xa90a, 0xa925, HB_Letter_Other},
+ {0xa926, 0xa92d, HB_Mark_NonSpacing},
+ {0xa92e, 0xa92f, HB_Punctuation_Other},
+ {0xa930, 0xa946, HB_Letter_Other},
+ {0xa947, 0xa951, HB_Mark_NonSpacing},
+ {0xa952, 0xa953, HB_Mark_SpacingCombining},
+ {0xa954, 0xa95e, HB_Other_NotAssigned},
+ {0xa95f, 0xa95f, HB_Punctuation_Other},
+ {0xa960, 0xa9ff, HB_Other_NotAssigned},
+ {0xaa00, 0xaa28, HB_Letter_Other},
+ {0xaa29, 0xaa2e, HB_Mark_NonSpacing},
+ {0xaa2f, 0xaa30, HB_Mark_SpacingCombining},
+ {0xaa31, 0xaa32, HB_Mark_NonSpacing},
+ {0xaa33, 0xaa34, HB_Mark_SpacingCombining},
+ {0xaa35, 0xaa36, HB_Mark_NonSpacing},
+ {0xaa37, 0xaa3f, HB_Other_NotAssigned},
+ {0xaa40, 0xaa42, HB_Letter_Other},
+ {0xaa43, 0xaa43, HB_Mark_NonSpacing},
+ {0xaa44, 0xaa4b, HB_Letter_Other},
+ {0xaa4c, 0xaa4c, HB_Mark_NonSpacing},
+ {0xaa4d, 0xaa4d, HB_Mark_SpacingCombining},
+ {0xaa4e, 0xaa4f, HB_Other_NotAssigned},
+ {0xaa50, 0xaa59, HB_Number_DecimalDigit},
+ {0xaa5a, 0xaa5b, HB_Other_NotAssigned},
+ {0xaa5c, 0xaa5f, HB_Punctuation_Other},
+ {0xaa60, 0xabff, HB_Other_NotAssigned},
+ {0xac00, 0xd7a3, HB_Letter_Other},
+ {0xd7a4, 0xd7ff, HB_Other_NotAssigned},
+ {0xd800, 0xdfff, HB_Other_Surrogate},
+ {0xe000, 0xf8ff, HB_Other_PrivateUse},
+ {0xf900, 0xfa2d, HB_Letter_Other},
+ {0xfa2e, 0xfa2f, HB_Other_NotAssigned},
+ {0xfa30, 0xfa6a, HB_Letter_Other},
+ {0xfa6b, 0xfa6f, HB_Other_NotAssigned},
+ {0xfa70, 0xfad9, HB_Letter_Other},
+ {0xfada, 0xfaff, HB_Other_NotAssigned},
+ {0xfb00, 0xfb06, HB_Letter_Lowercase},
+ {0xfb07, 0xfb12, HB_Other_NotAssigned},
+ {0xfb13, 0xfb17, HB_Letter_Lowercase},
+ {0xfb18, 0xfb1c, HB_Other_NotAssigned},
+ {0xfb1d, 0xfb1d, HB_Letter_Other},
+ {0xfb1e, 0xfb1e, HB_Mark_NonSpacing},
+ {0xfb1f, 0xfb28, HB_Letter_Other},
+ {0xfb29, 0xfb29, HB_Symbol_Math},
+ {0xfb2a, 0xfb36, HB_Letter_Other},
+ {0xfb37, 0xfb37, HB_Other_NotAssigned},
+ {0xfb38, 0xfb3c, HB_Letter_Other},
+ {0xfb3d, 0xfb3d, HB_Other_NotAssigned},
+ {0xfb3e, 0xfb3e, HB_Letter_Other},
+ {0xfb3f, 0xfb3f, HB_Other_NotAssigned},
+ {0xfb40, 0xfb41, HB_Letter_Other},
+ {0xfb42, 0xfb42, HB_Other_NotAssigned},
+ {0xfb43, 0xfb44, HB_Letter_Other},
+ {0xfb45, 0xfb45, HB_Other_NotAssigned},
+ {0xfb46, 0xfbb1, HB_Letter_Other},
+ {0xfbb2, 0xfbd2, HB_Other_NotAssigned},
+ {0xfbd3, 0xfd3d, HB_Letter_Other},
+ {0xfd3e, 0xfd3e, HB_Punctuation_Open},
+ {0xfd3f, 0xfd3f, HB_Punctuation_Close},
+ {0xfd40, 0xfd4f, HB_Other_NotAssigned},
+ {0xfd50, 0xfd8f, HB_Letter_Other},
+ {0xfd90, 0xfd91, HB_Other_NotAssigned},
+ {0xfd92, 0xfdc7, HB_Letter_Other},
+ {0xfdc8, 0xfdef, HB_Other_NotAssigned},
+ {0xfdf0, 0xfdfb, HB_Letter_Other},
+ {0xfdfc, 0xfdfc, HB_Symbol_Currency},
+ {0xfdfd, 0xfdfd, HB_Symbol_Other},
+ {0xfdfe, 0xfdff, HB_Other_NotAssigned},
+ {0xfe00, 0xfe0f, HB_Mark_NonSpacing},
+ {0xfe10, 0xfe16, HB_Punctuation_Other},
+ {0xfe17, 0xfe17, HB_Punctuation_Open},
+ {0xfe18, 0xfe18, HB_Punctuation_Close},
+ {0xfe19, 0xfe19, HB_Punctuation_Other},
+ {0xfe1a, 0xfe1f, HB_Other_NotAssigned},
+ {0xfe20, 0xfe26, HB_Mark_NonSpacing},
+ {0xfe27, 0xfe2f, HB_Other_NotAssigned},
+ {0xfe30, 0xfe30, HB_Punctuation_Other},
+ {0xfe31, 0xfe32, HB_Punctuation_Dash},
+ {0xfe33, 0xfe34, HB_Punctuation_Connector},
+ {0xfe35, 0xfe35, HB_Punctuation_Open},
+ {0xfe36, 0xfe36, HB_Punctuation_Close},
+ {0xfe37, 0xfe37, HB_Punctuation_Open},
+ {0xfe38, 0xfe38, HB_Punctuation_Close},
+ {0xfe39, 0xfe39, HB_Punctuation_Open},
+ {0xfe3a, 0xfe3a, HB_Punctuation_Close},
+ {0xfe3b, 0xfe3b, HB_Punctuation_Open},
+ {0xfe3c, 0xfe3c, HB_Punctuation_Close},
+ {0xfe3d, 0xfe3d, HB_Punctuation_Open},
+ {0xfe3e, 0xfe3e, HB_Punctuation_Close},
+ {0xfe3f, 0xfe3f, HB_Punctuation_Open},
+ {0xfe40, 0xfe40, HB_Punctuation_Close},
+ {0xfe41, 0xfe41, HB_Punctuation_Open},
+ {0xfe42, 0xfe42, HB_Punctuation_Close},
+ {0xfe43, 0xfe43, HB_Punctuation_Open},
+ {0xfe44, 0xfe44, HB_Punctuation_Close},
+ {0xfe45, 0xfe46, HB_Punctuation_Other},
+ {0xfe47, 0xfe47, HB_Punctuation_Open},
+ {0xfe48, 0xfe48, HB_Punctuation_Close},
+ {0xfe49, 0xfe4c, HB_Punctuation_Other},
+ {0xfe4d, 0xfe4f, HB_Punctuation_Connector},
+ {0xfe50, 0xfe52, HB_Punctuation_Other},
+ {0xfe53, 0xfe53, HB_Other_NotAssigned},
+ {0xfe54, 0xfe57, HB_Punctuation_Other},
+ {0xfe58, 0xfe58, HB_Punctuation_Dash},
+ {0xfe59, 0xfe59, HB_Punctuation_Open},
+ {0xfe5a, 0xfe5a, HB_Punctuation_Close},
+ {0xfe5b, 0xfe5b, HB_Punctuation_Open},
+ {0xfe5c, 0xfe5c, HB_Punctuation_Close},
+ {0xfe5d, 0xfe5d, HB_Punctuation_Open},
+ {0xfe5e, 0xfe5e, HB_Punctuation_Close},
+ {0xfe5f, 0xfe61, HB_Punctuation_Other},
+ {0xfe62, 0xfe62, HB_Symbol_Math},
+ {0xfe63, 0xfe63, HB_Punctuation_Dash},
+ {0xfe64, 0xfe66, HB_Symbol_Math},
+ {0xfe67, 0xfe67, HB_Other_NotAssigned},
+ {0xfe68, 0xfe68, HB_Punctuation_Other},
+ {0xfe69, 0xfe69, HB_Symbol_Currency},
+ {0xfe6a, 0xfe6b, HB_Punctuation_Other},
+ {0xfe6c, 0xfe6f, HB_Other_NotAssigned},
+ {0xfe70, 0xfe74, HB_Letter_Other},
+ {0xfe75, 0xfe75, HB_Other_NotAssigned},
+ {0xfe76, 0xfefc, HB_Letter_Other},
+ {0xfefd, 0xfefe, HB_Other_NotAssigned},
+ {0xfeff, 0xfeff, HB_Other_Format},
+ {0xff00, 0xff00, HB_Other_NotAssigned},
+ {0xff01, 0xff03, HB_Punctuation_Other},
+ {0xff04, 0xff04, HB_Symbol_Currency},
+ {0xff05, 0xff07, HB_Punctuation_Other},
+ {0xff08, 0xff08, HB_Punctuation_Open},
+ {0xff09, 0xff09, HB_Punctuation_Close},
+ {0xff0a, 0xff0a, HB_Punctuation_Other},
+ {0xff0b, 0xff0b, HB_Symbol_Math},
+ {0xff0c, 0xff0c, HB_Punctuation_Other},
+ {0xff0d, 0xff0d, HB_Punctuation_Dash},
+ {0xff0e, 0xff0f, HB_Punctuation_Other},
+ {0xff10, 0xff19, HB_Number_DecimalDigit},
+ {0xff1a, 0xff1b, HB_Punctuation_Other},
+ {0xff1c, 0xff1e, HB_Symbol_Math},
+ {0xff1f, 0xff20, HB_Punctuation_Other},
+ {0xff21, 0xff3a, HB_Letter_Uppercase},
+ {0xff3b, 0xff3b, HB_Punctuation_Open},
+ {0xff3c, 0xff3c, HB_Punctuation_Other},
+ {0xff3d, 0xff3d, HB_Punctuation_Close},
+ {0xff3e, 0xff3e, HB_Symbol_Modifier},
+ {0xff3f, 0xff3f, HB_Punctuation_Connector},
+ {0xff40, 0xff40, HB_Symbol_Modifier},
+ {0xff41, 0xff5a, HB_Letter_Lowercase},
+ {0xff5b, 0xff5b, HB_Punctuation_Open},
+ {0xff5c, 0xff5c, HB_Symbol_Math},
+ {0xff5d, 0xff5d, HB_Punctuation_Close},
+ {0xff5e, 0xff5e, HB_Symbol_Math},
+ {0xff5f, 0xff5f, HB_Punctuation_Open},
+ {0xff60, 0xff60, HB_Punctuation_Close},
+ {0xff61, 0xff61, HB_Punctuation_Other},
+ {0xff62, 0xff62, HB_Punctuation_Open},
+ {0xff63, 0xff63, HB_Punctuation_Close},
+ {0xff64, 0xff65, HB_Punctuation_Other},
+ {0xff66, 0xff6f, HB_Letter_Other},
+ {0xff70, 0xff70, HB_Letter_Modifier},
+ {0xff71, 0xff9d, HB_Letter_Other},
+ {0xff9e, 0xff9f, HB_Letter_Modifier},
+ {0xffa0, 0xffbe, HB_Letter_Other},
+ {0xffbf, 0xffc1, HB_Other_NotAssigned},
+ {0xffc2, 0xffc7, HB_Letter_Other},
+ {0xffc8, 0xffc9, HB_Other_NotAssigned},
+ {0xffca, 0xffcf, HB_Letter_Other},
+ {0xffd0, 0xffd1, HB_Other_NotAssigned},
+ {0xffd2, 0xffd7, HB_Letter_Other},
+ {0xffd8, 0xffd9, HB_Other_NotAssigned},
+ {0xffda, 0xffdc, HB_Letter_Other},
+ {0xffdd, 0xffdf, HB_Other_NotAssigned},
+ {0xffe0, 0xffe1, HB_Symbol_Currency},
+ {0xffe2, 0xffe2, HB_Symbol_Math},
+ {0xffe3, 0xffe3, HB_Symbol_Modifier},
+ {0xffe4, 0xffe4, HB_Symbol_Other},
+ {0xffe5, 0xffe6, HB_Symbol_Currency},
+ {0xffe7, 0xffe7, HB_Other_NotAssigned},
+ {0xffe8, 0xffe8, HB_Symbol_Other},
+ {0xffe9, 0xffec, HB_Symbol_Math},
+ {0xffed, 0xffee, HB_Symbol_Other},
+ {0xffef, 0xfff8, HB_Other_NotAssigned},
+ {0xfff9, 0xfffb, HB_Other_Format},
+ {0xfffc, 0xfffd, HB_Symbol_Other},
+ {0xfffe, 0xffff, HB_Other_NotAssigned},
+ {0x10000, 0x1000b, HB_Letter_Other},
+ {0x1000c, 0x1000c, HB_Other_NotAssigned},
+ {0x1000d, 0x10026, HB_Letter_Other},
+ {0x10027, 0x10027, HB_Other_NotAssigned},
+ {0x10028, 0x1003a, HB_Letter_Other},
+ {0x1003b, 0x1003b, HB_Other_NotAssigned},
+ {0x1003c, 0x1003d, HB_Letter_Other},
+ {0x1003e, 0x1003e, HB_Other_NotAssigned},
+ {0x1003f, 0x1004d, HB_Letter_Other},
+ {0x1004e, 0x1004f, HB_Other_NotAssigned},
+ {0x10050, 0x1005d, HB_Letter_Other},
+ {0x1005e, 0x1007f, HB_Other_NotAssigned},
+ {0x10080, 0x100fa, HB_Letter_Other},
+ {0x100fb, 0x100ff, HB_Other_NotAssigned},
+ {0x10100, 0x10101, HB_Punctuation_Other},
+ {0x10102, 0x10102, HB_Symbol_Other},
+ {0x10103, 0x10106, HB_Other_NotAssigned},
+ {0x10107, 0x10133, HB_Number_Other},
+ {0x10134, 0x10136, HB_Other_NotAssigned},
+ {0x10137, 0x1013f, HB_Symbol_Other},
+ {0x10140, 0x10174, HB_Number_Letter},
+ {0x10175, 0x10178, HB_Number_Other},
+ {0x10179, 0x10189, HB_Symbol_Other},
+ {0x1018a, 0x1018a, HB_Number_Other},
+ {0x1018b, 0x1018f, HB_Other_NotAssigned},
+ {0x10190, 0x1019b, HB_Symbol_Other},
+ {0x1019c, 0x101cf, HB_Other_NotAssigned},
+ {0x101d0, 0x101fc, HB_Symbol_Other},
+ {0x101fd, 0x101fd, HB_Mark_NonSpacing},
+ {0x101fe, 0x1027f, HB_Other_NotAssigned},
+ {0x10280, 0x1029c, HB_Letter_Other},
+ {0x1029d, 0x1029f, HB_Other_NotAssigned},
+ {0x102a0, 0x102d0, HB_Letter_Other},
+ {0x102d1, 0x102ff, HB_Other_NotAssigned},
+ {0x10300, 0x1031e, HB_Letter_Other},
+ {0x1031f, 0x1031f, HB_Other_NotAssigned},
+ {0x10320, 0x10323, HB_Number_Other},
+ {0x10324, 0x1032f, HB_Other_NotAssigned},
+ {0x10330, 0x10340, HB_Letter_Other},
+ {0x10341, 0x10341, HB_Number_Letter},
+ {0x10342, 0x10349, HB_Letter_Other},
+ {0x1034a, 0x1034a, HB_Number_Letter},
+ {0x1034b, 0x1037f, HB_Other_NotAssigned},
+ {0x10380, 0x1039d, HB_Letter_Other},
+ {0x1039e, 0x1039e, HB_Other_NotAssigned},
+ {0x1039f, 0x1039f, HB_Punctuation_Other},
+ {0x103a0, 0x103c3, HB_Letter_Other},
+ {0x103c4, 0x103c7, HB_Other_NotAssigned},
+ {0x103c8, 0x103cf, HB_Letter_Other},
+ {0x103d0, 0x103d0, HB_Punctuation_Other},
+ {0x103d1, 0x103d5, HB_Number_Letter},
+ {0x103d6, 0x103ff, HB_Other_NotAssigned},
+ {0x10400, 0x10427, HB_Letter_Uppercase},
+ {0x10428, 0x1044f, HB_Letter_Lowercase},
+ {0x10450, 0x1049d, HB_Letter_Other},
+ {0x1049e, 0x1049f, HB_Other_NotAssigned},
+ {0x104a0, 0x104a9, HB_Number_DecimalDigit},
+ {0x104aa, 0x107ff, HB_Other_NotAssigned},
+ {0x10800, 0x10805, HB_Letter_Other},
+ {0x10806, 0x10807, HB_Other_NotAssigned},
+ {0x10808, 0x10808, HB_Letter_Other},
+ {0x10809, 0x10809, HB_Other_NotAssigned},
+ {0x1080a, 0x10835, HB_Letter_Other},
+ {0x10836, 0x10836, HB_Other_NotAssigned},
+ {0x10837, 0x10838, HB_Letter_Other},
+ {0x10839, 0x1083b, HB_Other_NotAssigned},
+ {0x1083c, 0x1083c, HB_Letter_Other},
+ {0x1083d, 0x1083e, HB_Other_NotAssigned},
+ {0x1083f, 0x1083f, HB_Letter_Other},
+ {0x10840, 0x108ff, HB_Other_NotAssigned},
+ {0x10900, 0x10915, HB_Letter_Other},
+ {0x10916, 0x10919, HB_Number_Other},
+ {0x1091a, 0x1091e, HB_Other_NotAssigned},
+ {0x1091f, 0x1091f, HB_Punctuation_Other},
+ {0x10920, 0x10939, HB_Letter_Other},
+ {0x1093a, 0x1093e, HB_Other_NotAssigned},
+ {0x1093f, 0x1093f, HB_Punctuation_Other},
+ {0x10940, 0x109ff, HB_Other_NotAssigned},
+ {0x10a00, 0x10a00, HB_Letter_Other},
+ {0x10a01, 0x10a03, HB_Mark_NonSpacing},
+ {0x10a04, 0x10a04, HB_Other_NotAssigned},
+ {0x10a05, 0x10a06, HB_Mark_NonSpacing},
+ {0x10a07, 0x10a0b, HB_Other_NotAssigned},
+ {0x10a0c, 0x10a0f, HB_Mark_NonSpacing},
+ {0x10a10, 0x10a13, HB_Letter_Other},
+ {0x10a14, 0x10a14, HB_Other_NotAssigned},
+ {0x10a15, 0x10a17, HB_Letter_Other},
+ {0x10a18, 0x10a18, HB_Other_NotAssigned},
+ {0x10a19, 0x10a33, HB_Letter_Other},
+ {0x10a34, 0x10a37, HB_Other_NotAssigned},
+ {0x10a38, 0x10a3a, HB_Mark_NonSpacing},
+ {0x10a3b, 0x10a3e, HB_Other_NotAssigned},
+ {0x10a3f, 0x10a3f, HB_Mark_NonSpacing},
+ {0x10a40, 0x10a47, HB_Number_Other},
+ {0x10a48, 0x10a4f, HB_Other_NotAssigned},
+ {0x10a50, 0x10a58, HB_Punctuation_Other},
+ {0x10a59, 0x11fff, HB_Other_NotAssigned},
+ {0x12000, 0x1236e, HB_Letter_Other},
+ {0x1236f, 0x123ff, HB_Other_NotAssigned},
+ {0x12400, 0x12462, HB_Number_Letter},
+ {0x12463, 0x1246f, HB_Other_NotAssigned},
+ {0x12470, 0x12473, HB_Punctuation_Other},
+ {0x12474, 0x1cfff, HB_Other_NotAssigned},
+ {0x1d000, 0x1d0f5, HB_Symbol_Other},
+ {0x1d0f6, 0x1d0ff, HB_Other_NotAssigned},
+ {0x1d100, 0x1d126, HB_Symbol_Other},
+ {0x1d127, 0x1d128, HB_Other_NotAssigned},
+ {0x1d129, 0x1d164, HB_Symbol_Other},
+ {0x1d165, 0x1d166, HB_Mark_SpacingCombining},
+ {0x1d167, 0x1d169, HB_Mark_NonSpacing},
+ {0x1d16a, 0x1d16c, HB_Symbol_Other},
+ {0x1d16d, 0x1d172, HB_Mark_SpacingCombining},
+ {0x1d173, 0x1d17a, HB_Other_Format},
+ {0x1d17b, 0x1d182, HB_Mark_NonSpacing},
+ {0x1d183, 0x1d184, HB_Symbol_Other},
+ {0x1d185, 0x1d18b, HB_Mark_NonSpacing},
+ {0x1d18c, 0x1d1a9, HB_Symbol_Other},
+ {0x1d1aa, 0x1d1ad, HB_Mark_NonSpacing},
+ {0x1d1ae, 0x1d1dd, HB_Symbol_Other},
+ {0x1d1de, 0x1d1ff, HB_Other_NotAssigned},
+ {0x1d200, 0x1d241, HB_Symbol_Other},
+ {0x1d242, 0x1d244, HB_Mark_NonSpacing},
+ {0x1d245, 0x1d245, HB_Symbol_Other},
+ {0x1d246, 0x1d2ff, HB_Other_NotAssigned},
+ {0x1d300, 0x1d356, HB_Symbol_Other},
+ {0x1d357, 0x1d35f, HB_Other_NotAssigned},
+ {0x1d360, 0x1d371, HB_Number_Other},
+ {0x1d372, 0x1d3ff, HB_Other_NotAssigned},
+ {0x1d400, 0x1d419, HB_Letter_Uppercase},
+ {0x1d41a, 0x1d433, HB_Letter_Lowercase},
+ {0x1d434, 0x1d44d, HB_Letter_Uppercase},
+ {0x1d44e, 0x1d454, HB_Letter_Lowercase},
+ {0x1d455, 0x1d455, HB_Other_NotAssigned},
+ {0x1d456, 0x1d467, HB_Letter_Lowercase},
+ {0x1d468, 0x1d481, HB_Letter_Uppercase},
+ {0x1d482, 0x1d49b, HB_Letter_Lowercase},
+ {0x1d49c, 0x1d49c, HB_Letter_Uppercase},
+ {0x1d49d, 0x1d49d, HB_Other_NotAssigned},
+ {0x1d49e, 0x1d49f, HB_Letter_Uppercase},
+ {0x1d4a0, 0x1d4a1, HB_Other_NotAssigned},
+ {0x1d4a2, 0x1d4a2, HB_Letter_Uppercase},
+ {0x1d4a3, 0x1d4a4, HB_Other_NotAssigned},
+ {0x1d4a5, 0x1d4a6, HB_Letter_Uppercase},
+ {0x1d4a7, 0x1d4a8, HB_Other_NotAssigned},
+ {0x1d4a9, 0x1d4ac, HB_Letter_Uppercase},
+ {0x1d4ad, 0x1d4ad, HB_Other_NotAssigned},
+ {0x1d4ae, 0x1d4b5, HB_Letter_Uppercase},
+ {0x1d4b6, 0x1d4b9, HB_Letter_Lowercase},
+ {0x1d4ba, 0x1d4ba, HB_Other_NotAssigned},
+ {0x1d4bb, 0x1d4bb, HB_Letter_Lowercase},
+ {0x1d4bc, 0x1d4bc, HB_Other_NotAssigned},
+ {0x1d4bd, 0x1d4c3, HB_Letter_Lowercase},
+ {0x1d4c4, 0x1d4c4, HB_Other_NotAssigned},
+ {0x1d4c5, 0x1d4cf, HB_Letter_Lowercase},
+ {0x1d4d0, 0x1d4e9, HB_Letter_Uppercase},
+ {0x1d4ea, 0x1d503, HB_Letter_Lowercase},
+ {0x1d504, 0x1d505, HB_Letter_Uppercase},
+ {0x1d506, 0x1d506, HB_Other_NotAssigned},
+ {0x1d507, 0x1d50a, HB_Letter_Uppercase},
+ {0x1d50b, 0x1d50c, HB_Other_NotAssigned},
+ {0x1d50d, 0x1d514, HB_Letter_Uppercase},
+ {0x1d515, 0x1d515, HB_Other_NotAssigned},
+ {0x1d516, 0x1d51c, HB_Letter_Uppercase},
+ {0x1d51d, 0x1d51d, HB_Other_NotAssigned},
+ {0x1d51e, 0x1d537, HB_Letter_Lowercase},
+ {0x1d538, 0x1d539, HB_Letter_Uppercase},
+ {0x1d53a, 0x1d53a, HB_Other_NotAssigned},
+ {0x1d53b, 0x1d53e, HB_Letter_Uppercase},
+ {0x1d53f, 0x1d53f, HB_Other_NotAssigned},
+ {0x1d540, 0x1d544, HB_Letter_Uppercase},
+ {0x1d545, 0x1d545, HB_Other_NotAssigned},
+ {0x1d546, 0x1d546, HB_Letter_Uppercase},
+ {0x1d547, 0x1d549, HB_Other_NotAssigned},
+ {0x1d54a, 0x1d550, HB_Letter_Uppercase},
+ {0x1d551, 0x1d551, HB_Other_NotAssigned},
+ {0x1d552, 0x1d56b, HB_Letter_Lowercase},
+ {0x1d56c, 0x1d585, HB_Letter_Uppercase},
+ {0x1d586, 0x1d59f, HB_Letter_Lowercase},
+ {0x1d5a0, 0x1d5b9, HB_Letter_Uppercase},
+ {0x1d5ba, 0x1d5d3, HB_Letter_Lowercase},
+ {0x1d5d4, 0x1d5ed, HB_Letter_Uppercase},
+ {0x1d5ee, 0x1d607, HB_Letter_Lowercase},
+ {0x1d608, 0x1d621, HB_Letter_Uppercase},
+ {0x1d622, 0x1d63b, HB_Letter_Lowercase},
+ {0x1d63c, 0x1d655, HB_Letter_Uppercase},
+ {0x1d656, 0x1d66f, HB_Letter_Lowercase},
+ {0x1d670, 0x1d689, HB_Letter_Uppercase},
+ {0x1d68a, 0x1d6a5, HB_Letter_Lowercase},
+ {0x1d6a6, 0x1d6a7, HB_Other_NotAssigned},
+ {0x1d6a8, 0x1d6c0, HB_Letter_Uppercase},
+ {0x1d6c1, 0x1d6c1, HB_Symbol_Math},
+ {0x1d6c2, 0x1d6da, HB_Letter_Lowercase},
+ {0x1d6db, 0x1d6db, HB_Symbol_Math},
+ {0x1d6dc, 0x1d6e1, HB_Letter_Lowercase},
+ {0x1d6e2, 0x1d6fa, HB_Letter_Uppercase},
+ {0x1d6fb, 0x1d6fb, HB_Symbol_Math},
+ {0x1d6fc, 0x1d714, HB_Letter_Lowercase},
+ {0x1d715, 0x1d715, HB_Symbol_Math},
+ {0x1d716, 0x1d71b, HB_Letter_Lowercase},
+ {0x1d71c, 0x1d734, HB_Letter_Uppercase},
+ {0x1d735, 0x1d735, HB_Symbol_Math},
+ {0x1d736, 0x1d74e, HB_Letter_Lowercase},
+ {0x1d74f, 0x1d74f, HB_Symbol_Math},
+ {0x1d750, 0x1d755, HB_Letter_Lowercase},
+ {0x1d756, 0x1d76e, HB_Letter_Uppercase},
+ {0x1d76f, 0x1d76f, HB_Symbol_Math},
+ {0x1d770, 0x1d788, HB_Letter_Lowercase},
+ {0x1d789, 0x1d789, HB_Symbol_Math},
+ {0x1d78a, 0x1d78f, HB_Letter_Lowercase},
+ {0x1d790, 0x1d7a8, HB_Letter_Uppercase},
+ {0x1d7a9, 0x1d7a9, HB_Symbol_Math},
+ {0x1d7aa, 0x1d7c2, HB_Letter_Lowercase},
+ {0x1d7c3, 0x1d7c3, HB_Symbol_Math},
+ {0x1d7c4, 0x1d7c9, HB_Letter_Lowercase},
+ {0x1d7ca, 0x1d7ca, HB_Letter_Uppercase},
+ {0x1d7cb, 0x1d7cb, HB_Letter_Lowercase},
+ {0x1d7cc, 0x1d7cd, HB_Other_NotAssigned},
+ {0x1d7ce, 0x1d7ff, HB_Number_DecimalDigit},
+ {0x1d800, 0x1efff, HB_Other_NotAssigned},
+ {0x1f000, 0x1f02b, HB_Symbol_Other},
+ {0x1f02c, 0x1f02f, HB_Other_NotAssigned},
+ {0x1f030, 0x1f093, HB_Symbol_Other},
+ {0x1f094, 0x1ffff, HB_Other_NotAssigned},
+ {0x20000, 0x2a6d6, HB_Letter_Other},
+ {0x2a6d7, 0x2f7ff, HB_Other_NotAssigned},
+ {0x2f800, 0x2fa1d, HB_Letter_Other},
+ {0x2fa1e, 0xe0000, HB_Other_NotAssigned},
+ {0xe0001, 0xe0001, HB_Other_Format},
+ {0xe0002, 0xe001f, HB_Other_NotAssigned},
+ {0xe0020, 0xe007f, HB_Other_Format},
+ {0xe0080, 0xe00ff, HB_Other_NotAssigned},
+ {0xe0100, 0xe01ef, HB_Mark_NonSpacing},
+ {0xe01f0, 0xeffff, HB_Other_NotAssigned},
+ {0xf0000, 0xffffd, HB_Other_PrivateUse},
+ {0xffffe, 0xfffff, HB_Other_NotAssigned},
+ {0x100000, 0x10fffd, HB_Other_PrivateUse},
+ {0x10fffe, 0x10ffff, HB_Other_NotAssigned},
+};
+
+static const unsigned category_properties_count = 2849;
+
+#endif // CATEGORY_PROPERTIES_H_
diff --git a/third_party/harfbuzz/contrib/tables/combining-class-parse.py b/third_party/harfbuzz/contrib/tables/combining-class-parse.py
new file mode 100644
index 0000000..c591ddd
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/combining-class-parse.py
@@ -0,0 +1,34 @@
+import sys
+from unicode_parse_common import *
+
+# http://www.unicode.org/Public/5.1.0/ucd/extracted/DerivedCombiningClass.txt
+
+class IdentityMap(object):
+ def __getitem__(_, key):
+ return key
+
+def main(infile, outfile):
+ ranges = unicode_file_parse(infile, IdentityMap(), '0')
+ ranges = sort_and_merge(ranges)
+
+ print >>outfile, '// Generated from Unicode tables\n'
+ print >>outfile, '#ifndef COMBINING_PROPERTIES_H_'
+ print >>outfile, '#define COMBINING_PROPERTIES_H_\n'
+ print >>outfile, '#include <stdint.h>'
+ print >>outfile, 'struct combining_property {'
+ print >>outfile, ' uint32_t range_start;'
+ print >>outfile, ' uint32_t range_end;'
+ print >>outfile, ' uint8_t klass;'
+ print >>outfile, '};\n'
+ print >>outfile, 'static const struct combining_property combining_properties[] = {'
+ for (start, end, value) in ranges:
+ print >>outfile, ' {0x%x, 0x%x, %s},' % (start, end, value)
+ print >>outfile, '};\n'
+ print >>outfile, 'static const unsigned combining_properties_count = %d;\n' % len(ranges)
+ print >>outfile, '#endif // COMBINING_PROPERTIES_H_'
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print 'Usage: %s <input .txt> <output .h>' % sys.argv[0]
+ else:
+ main(file(sys.argv[1], 'r'), file(sys.argv[2], 'w+'))
diff --git a/third_party/harfbuzz/contrib/tables/combining-properties.h b/third_party/harfbuzz/contrib/tables/combining-properties.h
new file mode 100644
index 0000000..552ed35
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/combining-properties.h
@@ -0,0 +1,247 @@
+// Generated from Unicode tables
+
+#ifndef COMBINING_PROPERTIES_H_
+#define COMBINING_PROPERTIES_H_
+
+#include <stdint.h>
+struct combining_property {
+ uint32_t range_start;
+ uint32_t range_end;
+ uint8_t klass;
+};
+
+static const struct combining_property combining_properties[] = {
+ {0x300, 0x314, 230},
+ {0x315, 0x315, 232},
+ {0x316, 0x319, 220},
+ {0x31a, 0x31a, 232},
+ {0x31b, 0x31b, 216},
+ {0x31c, 0x320, 220},
+ {0x321, 0x322, 202},
+ {0x323, 0x326, 220},
+ {0x327, 0x328, 202},
+ {0x329, 0x333, 220},
+ {0x334, 0x338, 1},
+ {0x339, 0x33c, 220},
+ {0x33d, 0x344, 230},
+ {0x345, 0x345, 240},
+ {0x346, 0x346, 230},
+ {0x347, 0x349, 220},
+ {0x34a, 0x34c, 230},
+ {0x34d, 0x34e, 220},
+ {0x350, 0x352, 230},
+ {0x353, 0x356, 220},
+ {0x357, 0x357, 230},
+ {0x358, 0x358, 232},
+ {0x359, 0x35a, 220},
+ {0x35b, 0x35b, 230},
+ {0x35c, 0x35c, 233},
+ {0x35d, 0x35e, 234},
+ {0x35f, 0x35f, 233},
+ {0x360, 0x361, 234},
+ {0x362, 0x362, 233},
+ {0x363, 0x36f, 230},
+ {0x483, 0x487, 230},
+ {0x591, 0x591, 220},
+ {0x592, 0x595, 230},
+ {0x596, 0x596, 220},
+ {0x597, 0x599, 230},
+ {0x59a, 0x59a, 222},
+ {0x59b, 0x59b, 220},
+ {0x59c, 0x5a1, 230},
+ {0x5a2, 0x5a7, 220},
+ {0x5a8, 0x5a9, 230},
+ {0x5aa, 0x5aa, 220},
+ {0x5ab, 0x5ac, 230},
+ {0x5ad, 0x5ad, 222},
+ {0x5ae, 0x5ae, 228},
+ {0x5af, 0x5af, 230},
+ {0x5b0, 0x5b0, 10},
+ {0x5b1, 0x5b1, 11},
+ {0x5b2, 0x5b2, 12},
+ {0x5b3, 0x5b3, 13},
+ {0x5b4, 0x5b4, 14},
+ {0x5b5, 0x5b5, 15},
+ {0x5b6, 0x5b6, 16},
+ {0x5b7, 0x5b7, 17},
+ {0x5b8, 0x5b8, 18},
+ {0x5b9, 0x5ba, 19},
+ {0x5bb, 0x5bb, 20},
+ {0x5bc, 0x5bc, 21},
+ {0x5bd, 0x5bd, 22},
+ {0x5bf, 0x5bf, 23},
+ {0x5c1, 0x5c1, 24},
+ {0x5c2, 0x5c2, 25},
+ {0x5c4, 0x5c4, 230},
+ {0x5c5, 0x5c5, 220},
+ {0x5c7, 0x5c7, 18},
+ {0x610, 0x617, 230},
+ {0x618, 0x618, 30},
+ {0x619, 0x619, 31},
+ {0x61a, 0x61a, 32},
+ {0x64b, 0x64b, 27},
+ {0x64c, 0x64c, 28},
+ {0x64d, 0x64d, 29},
+ {0x64e, 0x64e, 30},
+ {0x64f, 0x64f, 31},
+ {0x650, 0x650, 32},
+ {0x651, 0x651, 33},
+ {0x652, 0x652, 34},
+ {0x653, 0x654, 230},
+ {0x655, 0x656, 220},
+ {0x657, 0x65b, 230},
+ {0x65c, 0x65c, 220},
+ {0x65d, 0x65e, 230},
+ {0x670, 0x670, 35},
+ {0x6d6, 0x6dc, 230},
+ {0x6df, 0x6e2, 230},
+ {0x6e3, 0x6e3, 220},
+ {0x6e4, 0x6e4, 230},
+ {0x6e7, 0x6e8, 230},
+ {0x6ea, 0x6ea, 220},
+ {0x6eb, 0x6ec, 230},
+ {0x6ed, 0x6ed, 220},
+ {0x711, 0x711, 36},
+ {0x730, 0x730, 230},
+ {0x731, 0x731, 220},
+ {0x732, 0x733, 230},
+ {0x734, 0x734, 220},
+ {0x735, 0x736, 230},
+ {0x737, 0x739, 220},
+ {0x73a, 0x73a, 230},
+ {0x73b, 0x73c, 220},
+ {0x73d, 0x73d, 230},
+ {0x73e, 0x73e, 220},
+ {0x73f, 0x741, 230},
+ {0x742, 0x742, 220},
+ {0x743, 0x743, 230},
+ {0x744, 0x744, 220},
+ {0x745, 0x745, 230},
+ {0x746, 0x746, 220},
+ {0x747, 0x747, 230},
+ {0x748, 0x748, 220},
+ {0x749, 0x74a, 230},
+ {0x7eb, 0x7f1, 230},
+ {0x7f2, 0x7f2, 220},
+ {0x7f3, 0x7f3, 230},
+ {0x93c, 0x93c, 7},
+ {0x94d, 0x94d, 9},
+ {0x951, 0x951, 230},
+ {0x952, 0x952, 220},
+ {0x953, 0x954, 230},
+ {0x9bc, 0x9bc, 7},
+ {0x9cd, 0x9cd, 9},
+ {0xa3c, 0xa3c, 7},
+ {0xa4d, 0xa4d, 9},
+ {0xabc, 0xabc, 7},
+ {0xacd, 0xacd, 9},
+ {0xb3c, 0xb3c, 7},
+ {0xb4d, 0xb4d, 9},
+ {0xbcd, 0xbcd, 9},
+ {0xc4d, 0xc4d, 9},
+ {0xc55, 0xc55, 84},
+ {0xc56, 0xc56, 91},
+ {0xcbc, 0xcbc, 7},
+ {0xccd, 0xccd, 9},
+ {0xd4d, 0xd4d, 9},
+ {0xdca, 0xdca, 9},
+ {0xe38, 0xe39, 103},
+ {0xe3a, 0xe3a, 9},
+ {0xe48, 0xe4b, 107},
+ {0xeb8, 0xeb9, 118},
+ {0xec8, 0xecb, 122},
+ {0xf18, 0xf19, 220},
+ {0xf35, 0xf35, 220},
+ {0xf37, 0xf37, 220},
+ {0xf39, 0xf39, 216},
+ {0xf71, 0xf71, 129},
+ {0xf72, 0xf72, 130},
+ {0xf74, 0xf74, 132},
+ {0xf7a, 0xf7d, 130},
+ {0xf80, 0xf80, 130},
+ {0xf82, 0xf83, 230},
+ {0xf84, 0xf84, 9},
+ {0xf86, 0xf87, 230},
+ {0xfc6, 0xfc6, 220},
+ {0x1037, 0x1037, 7},
+ {0x1039, 0x103a, 9},
+ {0x108d, 0x108d, 220},
+ {0x135f, 0x135f, 230},
+ {0x1714, 0x1714, 9},
+ {0x1734, 0x1734, 9},
+ {0x17d2, 0x17d2, 9},
+ {0x17dd, 0x17dd, 230},
+ {0x18a9, 0x18a9, 228},
+ {0x1939, 0x1939, 222},
+ {0x193a, 0x193a, 230},
+ {0x193b, 0x193b, 220},
+ {0x1a17, 0x1a17, 230},
+ {0x1a18, 0x1a18, 220},
+ {0x1b34, 0x1b34, 7},
+ {0x1b44, 0x1b44, 9},
+ {0x1b6b, 0x1b6b, 230},
+ {0x1b6c, 0x1b6c, 220},
+ {0x1b6d, 0x1b73, 230},
+ {0x1baa, 0x1baa, 9},
+ {0x1c37, 0x1c37, 7},
+ {0x1dc0, 0x1dc1, 230},
+ {0x1dc2, 0x1dc2, 220},
+ {0x1dc3, 0x1dc9, 230},
+ {0x1dca, 0x1dca, 220},
+ {0x1dcb, 0x1dcc, 230},
+ {0x1dcd, 0x1dcd, 234},
+ {0x1dce, 0x1dce, 214},
+ {0x1dcf, 0x1dcf, 220},
+ {0x1dd0, 0x1dd0, 202},
+ {0x1dd1, 0x1de6, 230},
+ {0x1dfe, 0x1dfe, 230},
+ {0x1dff, 0x1dff, 220},
+ {0x20d0, 0x20d1, 230},
+ {0x20d2, 0x20d3, 1},
+ {0x20d4, 0x20d7, 230},
+ {0x20d8, 0x20da, 1},
+ {0x20db, 0x20dc, 230},
+ {0x20e1, 0x20e1, 230},
+ {0x20e5, 0x20e6, 1},
+ {0x20e7, 0x20e7, 230},
+ {0x20e8, 0x20e8, 220},
+ {0x20e9, 0x20e9, 230},
+ {0x20ea, 0x20eb, 1},
+ {0x20ec, 0x20ef, 220},
+ {0x20f0, 0x20f0, 230},
+ {0x2de0, 0x2dff, 230},
+ {0x302a, 0x302a, 218},
+ {0x302b, 0x302b, 228},
+ {0x302c, 0x302c, 232},
+ {0x302d, 0x302d, 222},
+ {0x302e, 0x302f, 224},
+ {0x3099, 0x309a, 8},
+ {0xa66f, 0xa66f, 230},
+ {0xa67c, 0xa67d, 230},
+ {0xa806, 0xa806, 9},
+ {0xa8c4, 0xa8c4, 9},
+ {0xa92b, 0xa92d, 220},
+ {0xa953, 0xa953, 9},
+ {0xfb1e, 0xfb1e, 26},
+ {0xfe20, 0xfe26, 230},
+ {0x101fd, 0x101fd, 220},
+ {0x10a0d, 0x10a0d, 220},
+ {0x10a0f, 0x10a0f, 230},
+ {0x10a38, 0x10a38, 230},
+ {0x10a39, 0x10a39, 1},
+ {0x10a3a, 0x10a3a, 220},
+ {0x10a3f, 0x10a3f, 9},
+ {0x1d165, 0x1d166, 216},
+ {0x1d167, 0x1d169, 1},
+ {0x1d16d, 0x1d16d, 226},
+ {0x1d16e, 0x1d172, 216},
+ {0x1d17b, 0x1d182, 220},
+ {0x1d185, 0x1d189, 230},
+ {0x1d18a, 0x1d18b, 220},
+ {0x1d1aa, 0x1d1ad, 230},
+ {0x1d242, 0x1d244, 230},
+};
+
+static const unsigned combining_properties_count = 229;
+
+#endif // COMBINING_PROPERTIES_H_
diff --git a/third_party/harfbuzz/contrib/tables/grapheme-break-parse.py b/third_party/harfbuzz/contrib/tables/grapheme-break-parse.py
new file mode 100644
index 0000000..a4b3534
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/grapheme-break-parse.py
@@ -0,0 +1,45 @@
+import sys
+from unicode_parse_common import *
+
+# http://www.unicode.org/Public/UNIDATA/auxiliary/GraphemeBreakProperty.txt
+
+property_to_harfbuzz = {
+ 'CR': 'HB_Grapheme_CR',
+ 'LF': 'HB_Grapheme_LF',
+ 'Control': 'HB_Grapheme_Control',
+ 'Extend': 'HB_Grapheme_Extend',
+ 'Prepend': 'HB_Grapheme_Other',
+ 'SpacingMark': 'HB_Grapheme_Other',
+ 'L': 'HB_Grapheme_L',
+ 'V': 'HB_Grapheme_V',
+ 'T': 'HB_Grapheme_T',
+ 'LV': 'HB_Grapheme_LV',
+ 'LVT': 'HB_Grapheme_LVT',
+}
+
+def main(infile, outfile):
+ ranges = unicode_file_parse(infile, property_to_harfbuzz)
+ ranges.sort()
+
+ print >>outfile, '// Generated from Unicode Grapheme break tables\n'
+ print >>outfile, '#ifndef GRAPHEME_BREAK_PROPERTY_H_'
+ print >>outfile, '#define GRAPHEME_BREAK_PROPERTY_H_\n'
+ print >>outfile, '#include <stdint.h>'
+ print >>outfile, '#include "harfbuzz-external.h"\n'
+ print >>outfile, 'struct grapheme_break_property {'
+ print >>outfile, ' uint32_t range_start;'
+ print >>outfile, ' uint32_t range_end;'
+ print >>outfile, ' HB_GraphemeClass klass;'
+ print >>outfile, '};\n'
+ print >>outfile, 'static const struct grapheme_break_property grapheme_break_properties[] = {'
+ for (start, end, value) in ranges:
+ print >>outfile, ' {0x%x, 0x%x, %s},' % (start, end, value)
+ print >>outfile, '};\n'
+ print >>outfile, 'static const unsigned grapheme_break_properties_count = %d;\n' % len(ranges)
+ print >>outfile, '#endif // GRAPHEME_BREAK_PROPERTY_H_'
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print 'Usage: %s <input .txt> <output .h>' % sys.argv[0]
+ else:
+ main(file(sys.argv[1], 'r'), file(sys.argv[2], 'w+'))
diff --git a/third_party/harfbuzz/contrib/tables/grapheme-break-properties.h b/third_party/harfbuzz/contrib/tables/grapheme-break-properties.h
new file mode 100644
index 0000000..73f47d4
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/grapheme-break-properties.h
@@ -0,0 +1,1113 @@
+// Generated from Unicode Grapheme break tables
+
+#ifndef GRAPHEME_BREAK_PROPERTY_H_
+#define GRAPHEME_BREAK_PROPERTY_H_
+
+#include <stdint.h>
+#include "harfbuzz-external.h"
+
+struct grapheme_break_property {
+ uint32_t range_start;
+ uint32_t range_end;
+ HB_GraphemeClass klass;
+};
+
+static const struct grapheme_break_property grapheme_break_properties[] = {
+ {0x0, 0x9, HB_Grapheme_Control},
+ {0xa, 0xa, HB_Grapheme_LF},
+ {0xb, 0xc, HB_Grapheme_Control},
+ {0xd, 0xd, HB_Grapheme_CR},
+ {0xe, 0x1f, HB_Grapheme_Control},
+ {0x7f, 0x9f, HB_Grapheme_Control},
+ {0xad, 0xad, HB_Grapheme_Control},
+ {0x300, 0x36f, HB_Grapheme_Extend},
+ {0x483, 0x487, HB_Grapheme_Extend},
+ {0x488, 0x489, HB_Grapheme_Extend},
+ {0x591, 0x5bd, HB_Grapheme_Extend},
+ {0x5bf, 0x5bf, HB_Grapheme_Extend},
+ {0x5c1, 0x5c2, HB_Grapheme_Extend},
+ {0x5c4, 0x5c5, HB_Grapheme_Extend},
+ {0x5c7, 0x5c7, HB_Grapheme_Extend},
+ {0x600, 0x603, HB_Grapheme_Control},
+ {0x610, 0x61a, HB_Grapheme_Extend},
+ {0x64b, 0x65e, HB_Grapheme_Extend},
+ {0x670, 0x670, HB_Grapheme_Extend},
+ {0x6d6, 0x6dc, HB_Grapheme_Extend},
+ {0x6dd, 0x6dd, HB_Grapheme_Control},
+ {0x6de, 0x6de, HB_Grapheme_Extend},
+ {0x6df, 0x6e4, HB_Grapheme_Extend},
+ {0x6e7, 0x6e8, HB_Grapheme_Extend},
+ {0x6ea, 0x6ed, HB_Grapheme_Extend},
+ {0x70f, 0x70f, HB_Grapheme_Control},
+ {0x711, 0x711, HB_Grapheme_Extend},
+ {0x730, 0x74a, HB_Grapheme_Extend},
+ {0x7a6, 0x7b0, HB_Grapheme_Extend},
+ {0x7eb, 0x7f3, HB_Grapheme_Extend},
+ {0x901, 0x902, HB_Grapheme_Extend},
+ {0x903, 0x903, HB_Grapheme_Other},
+ {0x93c, 0x93c, HB_Grapheme_Extend},
+ {0x93e, 0x940, HB_Grapheme_Other},
+ {0x941, 0x948, HB_Grapheme_Extend},
+ {0x949, 0x94c, HB_Grapheme_Other},
+ {0x94d, 0x94d, HB_Grapheme_Extend},
+ {0x951, 0x954, HB_Grapheme_Extend},
+ {0x962, 0x963, HB_Grapheme_Extend},
+ {0x981, 0x981, HB_Grapheme_Extend},
+ {0x982, 0x983, HB_Grapheme_Other},
+ {0x9bc, 0x9bc, HB_Grapheme_Extend},
+ {0x9be, 0x9be, HB_Grapheme_Extend},
+ {0x9bf, 0x9c0, HB_Grapheme_Other},
+ {0x9c1, 0x9c4, HB_Grapheme_Extend},
+ {0x9c7, 0x9c8, HB_Grapheme_Other},
+ {0x9cb, 0x9cc, HB_Grapheme_Other},
+ {0x9cd, 0x9cd, HB_Grapheme_Extend},
+ {0x9d7, 0x9d7, HB_Grapheme_Extend},
+ {0x9e2, 0x9e3, HB_Grapheme_Extend},
+ {0xa01, 0xa02, HB_Grapheme_Extend},
+ {0xa03, 0xa03, HB_Grapheme_Other},
+ {0xa3c, 0xa3c, HB_Grapheme_Extend},
+ {0xa3e, 0xa40, HB_Grapheme_Other},
+ {0xa41, 0xa42, HB_Grapheme_Extend},
+ {0xa47, 0xa48, HB_Grapheme_Extend},
+ {0xa4b, 0xa4d, HB_Grapheme_Extend},
+ {0xa51, 0xa51, HB_Grapheme_Extend},
+ {0xa70, 0xa71, HB_Grapheme_Extend},
+ {0xa75, 0xa75, HB_Grapheme_Extend},
+ {0xa81, 0xa82, HB_Grapheme_Extend},
+ {0xa83, 0xa83, HB_Grapheme_Other},
+ {0xabc, 0xabc, HB_Grapheme_Extend},
+ {0xabe, 0xac0, HB_Grapheme_Other},
+ {0xac1, 0xac5, HB_Grapheme_Extend},
+ {0xac7, 0xac8, HB_Grapheme_Extend},
+ {0xac9, 0xac9, HB_Grapheme_Other},
+ {0xacb, 0xacc, HB_Grapheme_Other},
+ {0xacd, 0xacd, HB_Grapheme_Extend},
+ {0xae2, 0xae3, HB_Grapheme_Extend},
+ {0xb01, 0xb01, HB_Grapheme_Extend},
+ {0xb02, 0xb03, HB_Grapheme_Other},
+ {0xb3c, 0xb3c, HB_Grapheme_Extend},
+ {0xb3e, 0xb3e, HB_Grapheme_Extend},
+ {0xb3f, 0xb3f, HB_Grapheme_Extend},
+ {0xb40, 0xb40, HB_Grapheme_Other},
+ {0xb41, 0xb44, HB_Grapheme_Extend},
+ {0xb47, 0xb48, HB_Grapheme_Other},
+ {0xb4b, 0xb4c, HB_Grapheme_Other},
+ {0xb4d, 0xb4d, HB_Grapheme_Extend},
+ {0xb56, 0xb56, HB_Grapheme_Extend},
+ {0xb57, 0xb57, HB_Grapheme_Extend},
+ {0xb62, 0xb63, HB_Grapheme_Extend},
+ {0xb82, 0xb82, HB_Grapheme_Extend},
+ {0xbbe, 0xbbe, HB_Grapheme_Extend},
+ {0xbbf, 0xbbf, HB_Grapheme_Other},
+ {0xbc0, 0xbc0, HB_Grapheme_Extend},
+ {0xbc1, 0xbc2, HB_Grapheme_Other},
+ {0xbc6, 0xbc8, HB_Grapheme_Other},
+ {0xbca, 0xbcc, HB_Grapheme_Other},
+ {0xbcd, 0xbcd, HB_Grapheme_Extend},
+ {0xbd7, 0xbd7, HB_Grapheme_Extend},
+ {0xc01, 0xc03, HB_Grapheme_Other},
+ {0xc3e, 0xc40, HB_Grapheme_Extend},
+ {0xc41, 0xc44, HB_Grapheme_Other},
+ {0xc46, 0xc48, HB_Grapheme_Extend},
+ {0xc4a, 0xc4d, HB_Grapheme_Extend},
+ {0xc55, 0xc56, HB_Grapheme_Extend},
+ {0xc62, 0xc63, HB_Grapheme_Extend},
+ {0xc82, 0xc83, HB_Grapheme_Other},
+ {0xcbc, 0xcbc, HB_Grapheme_Extend},
+ {0xcbe, 0xcbe, HB_Grapheme_Other},
+ {0xcbf, 0xcbf, HB_Grapheme_Extend},
+ {0xcc0, 0xcc1, HB_Grapheme_Other},
+ {0xcc2, 0xcc2, HB_Grapheme_Extend},
+ {0xcc3, 0xcc4, HB_Grapheme_Other},
+ {0xcc6, 0xcc6, HB_Grapheme_Extend},
+ {0xcc7, 0xcc8, HB_Grapheme_Other},
+ {0xcca, 0xccb, HB_Grapheme_Other},
+ {0xccc, 0xccd, HB_Grapheme_Extend},
+ {0xcd5, 0xcd6, HB_Grapheme_Extend},
+ {0xce2, 0xce3, HB_Grapheme_Extend},
+ {0xd02, 0xd03, HB_Grapheme_Other},
+ {0xd3e, 0xd3e, HB_Grapheme_Extend},
+ {0xd3f, 0xd40, HB_Grapheme_Other},
+ {0xd41, 0xd44, HB_Grapheme_Extend},
+ {0xd46, 0xd48, HB_Grapheme_Other},
+ {0xd4a, 0xd4c, HB_Grapheme_Other},
+ {0xd4d, 0xd4d, HB_Grapheme_Extend},
+ {0xd57, 0xd57, HB_Grapheme_Extend},
+ {0xd62, 0xd63, HB_Grapheme_Extend},
+ {0xd82, 0xd83, HB_Grapheme_Other},
+ {0xdca, 0xdca, HB_Grapheme_Extend},
+ {0xdcf, 0xdcf, HB_Grapheme_Extend},
+ {0xdd0, 0xdd1, HB_Grapheme_Other},
+ {0xdd2, 0xdd4, HB_Grapheme_Extend},
+ {0xdd6, 0xdd6, HB_Grapheme_Extend},
+ {0xdd8, 0xdde, HB_Grapheme_Other},
+ {0xddf, 0xddf, HB_Grapheme_Extend},
+ {0xdf2, 0xdf3, HB_Grapheme_Other},
+ {0xe30, 0xe30, HB_Grapheme_Extend},
+ {0xe31, 0xe31, HB_Grapheme_Extend},
+ {0xe32, 0xe33, HB_Grapheme_Extend},
+ {0xe34, 0xe3a, HB_Grapheme_Extend},
+ {0xe40, 0xe44, HB_Grapheme_Other},
+ {0xe45, 0xe45, HB_Grapheme_Extend},
+ {0xe47, 0xe4e, HB_Grapheme_Extend},
+ {0xeb0, 0xeb0, HB_Grapheme_Extend},
+ {0xeb1, 0xeb1, HB_Grapheme_Extend},
+ {0xeb2, 0xeb3, HB_Grapheme_Extend},
+ {0xeb4, 0xeb9, HB_Grapheme_Extend},
+ {0xebb, 0xebc, HB_Grapheme_Extend},
+ {0xec0, 0xec4, HB_Grapheme_Other},
+ {0xec8, 0xecd, HB_Grapheme_Extend},
+ {0xf18, 0xf19, HB_Grapheme_Extend},
+ {0xf35, 0xf35, HB_Grapheme_Extend},
+ {0xf37, 0xf37, HB_Grapheme_Extend},
+ {0xf39, 0xf39, HB_Grapheme_Extend},
+ {0xf3e, 0xf3f, HB_Grapheme_Other},
+ {0xf71, 0xf7e, HB_Grapheme_Extend},
+ {0xf7f, 0xf7f, HB_Grapheme_Other},
+ {0xf80, 0xf84, HB_Grapheme_Extend},
+ {0xf86, 0xf87, HB_Grapheme_Extend},
+ {0xf90, 0xf97, HB_Grapheme_Extend},
+ {0xf99, 0xfbc, HB_Grapheme_Extend},
+ {0xfc6, 0xfc6, HB_Grapheme_Extend},
+ {0x102b, 0x102c, HB_Grapheme_Other},
+ {0x102d, 0x1030, HB_Grapheme_Extend},
+ {0x1031, 0x1031, HB_Grapheme_Other},
+ {0x1032, 0x1037, HB_Grapheme_Extend},
+ {0x1038, 0x1038, HB_Grapheme_Other},
+ {0x1039, 0x103a, HB_Grapheme_Extend},
+ {0x103b, 0x103c, HB_Grapheme_Other},
+ {0x103d, 0x103e, HB_Grapheme_Extend},
+ {0x1056, 0x1057, HB_Grapheme_Other},
+ {0x1058, 0x1059, HB_Grapheme_Extend},
+ {0x105e, 0x1060, HB_Grapheme_Extend},
+ {0x1062, 0x1064, HB_Grapheme_Other},
+ {0x1067, 0x106d, HB_Grapheme_Other},
+ {0x1071, 0x1074, HB_Grapheme_Extend},
+ {0x1082, 0x1082, HB_Grapheme_Extend},
+ {0x1083, 0x1084, HB_Grapheme_Other},
+ {0x1085, 0x1086, HB_Grapheme_Extend},
+ {0x1087, 0x108c, HB_Grapheme_Other},
+ {0x108d, 0x108d, HB_Grapheme_Extend},
+ {0x108f, 0x108f, HB_Grapheme_Other},
+ {0x1100, 0x1159, HB_Grapheme_L},
+ {0x115f, 0x115f, HB_Grapheme_L},
+ {0x1160, 0x11a2, HB_Grapheme_V},
+ {0x11a8, 0x11f9, HB_Grapheme_T},
+ {0x135f, 0x135f, HB_Grapheme_Extend},
+ {0x1712, 0x1714, HB_Grapheme_Extend},
+ {0x1732, 0x1734, HB_Grapheme_Extend},
+ {0x1752, 0x1753, HB_Grapheme_Extend},
+ {0x1772, 0x1773, HB_Grapheme_Extend},
+ {0x17b4, 0x17b5, HB_Grapheme_Control},
+ {0x17b6, 0x17b6, HB_Grapheme_Other},
+ {0x17b7, 0x17bd, HB_Grapheme_Extend},
+ {0x17be, 0x17c5, HB_Grapheme_Other},
+ {0x17c6, 0x17c6, HB_Grapheme_Extend},
+ {0x17c7, 0x17c8, HB_Grapheme_Other},
+ {0x17c9, 0x17d3, HB_Grapheme_Extend},
+ {0x17dd, 0x17dd, HB_Grapheme_Extend},
+ {0x180b, 0x180d, HB_Grapheme_Extend},
+ {0x18a9, 0x18a9, HB_Grapheme_Extend},
+ {0x1920, 0x1922, HB_Grapheme_Extend},
+ {0x1923, 0x1926, HB_Grapheme_Other},
+ {0x1927, 0x1928, HB_Grapheme_Extend},
+ {0x1929, 0x192b, HB_Grapheme_Other},
+ {0x1930, 0x1931, HB_Grapheme_Other},
+ {0x1932, 0x1932, HB_Grapheme_Extend},
+ {0x1933, 0x1938, HB_Grapheme_Other},
+ {0x1939, 0x193b, HB_Grapheme_Extend},
+ {0x19b0, 0x19c0, HB_Grapheme_Other},
+ {0x19c8, 0x19c9, HB_Grapheme_Other},
+ {0x1a17, 0x1a18, HB_Grapheme_Extend},
+ {0x1a19, 0x1a1b, HB_Grapheme_Other},
+ {0x1b00, 0x1b03, HB_Grapheme_Extend},
+ {0x1b04, 0x1b04, HB_Grapheme_Other},
+ {0x1b34, 0x1b34, HB_Grapheme_Extend},
+ {0x1b35, 0x1b35, HB_Grapheme_Other},
+ {0x1b36, 0x1b3a, HB_Grapheme_Extend},
+ {0x1b3b, 0x1b3b, HB_Grapheme_Other},
+ {0x1b3c, 0x1b3c, HB_Grapheme_Extend},
+ {0x1b3d, 0x1b41, HB_Grapheme_Other},
+ {0x1b42, 0x1b42, HB_Grapheme_Extend},
+ {0x1b43, 0x1b44, HB_Grapheme_Other},
+ {0x1b6b, 0x1b73, HB_Grapheme_Extend},
+ {0x1b80, 0x1b81, HB_Grapheme_Extend},
+ {0x1b82, 0x1b82, HB_Grapheme_Other},
+ {0x1ba1, 0x1ba1, HB_Grapheme_Other},
+ {0x1ba2, 0x1ba5, HB_Grapheme_Extend},
+ {0x1ba6, 0x1ba7, HB_Grapheme_Other},
+ {0x1ba8, 0x1ba9, HB_Grapheme_Extend},
+ {0x1baa, 0x1baa, HB_Grapheme_Other},
+ {0x1c24, 0x1c2b, HB_Grapheme_Other},
+ {0x1c2c, 0x1c33, HB_Grapheme_Extend},
+ {0x1c34, 0x1c35, HB_Grapheme_Other},
+ {0x1c36, 0x1c37, HB_Grapheme_Extend},
+ {0x1dc0, 0x1de6, HB_Grapheme_Extend},
+ {0x1dfe, 0x1dff, HB_Grapheme_Extend},
+ {0x200b, 0x200b, HB_Grapheme_Control},
+ {0x200c, 0x200d, HB_Grapheme_Extend},
+ {0x200e, 0x200f, HB_Grapheme_Control},
+ {0x2028, 0x2028, HB_Grapheme_Control},
+ {0x2029, 0x2029, HB_Grapheme_Control},
+ {0x202a, 0x202e, HB_Grapheme_Control},
+ {0x2060, 0x2064, HB_Grapheme_Control},
+ {0x206a, 0x206f, HB_Grapheme_Control},
+ {0x20d0, 0x20dc, HB_Grapheme_Extend},
+ {0x20dd, 0x20e0, HB_Grapheme_Extend},
+ {0x20e1, 0x20e1, HB_Grapheme_Extend},
+ {0x20e2, 0x20e4, HB_Grapheme_Extend},
+ {0x20e5, 0x20f0, HB_Grapheme_Extend},
+ {0x2de0, 0x2dff, HB_Grapheme_Extend},
+ {0x302a, 0x302f, HB_Grapheme_Extend},
+ {0x3099, 0x309a, HB_Grapheme_Extend},
+ {0xa66f, 0xa66f, HB_Grapheme_Extend},
+ {0xa670, 0xa672, HB_Grapheme_Extend},
+ {0xa67c, 0xa67d, HB_Grapheme_Extend},
+ {0xa802, 0xa802, HB_Grapheme_Extend},
+ {0xa806, 0xa806, HB_Grapheme_Extend},
+ {0xa80b, 0xa80b, HB_Grapheme_Extend},
+ {0xa823, 0xa824, HB_Grapheme_Other},
+ {0xa825, 0xa826, HB_Grapheme_Extend},
+ {0xa827, 0xa827, HB_Grapheme_Other},
+ {0xa880, 0xa881, HB_Grapheme_Other},
+ {0xa8b4, 0xa8c3, HB_Grapheme_Other},
+ {0xa8c4, 0xa8c4, HB_Grapheme_Extend},
+ {0xa926, 0xa92d, HB_Grapheme_Extend},
+ {0xa947, 0xa951, HB_Grapheme_Extend},
+ {0xa952, 0xa953, HB_Grapheme_Other},
+ {0xaa29, 0xaa2e, HB_Grapheme_Extend},
+ {0xaa2f, 0xaa30, HB_Grapheme_Other},
+ {0xaa31, 0xaa32, HB_Grapheme_Extend},
+ {0xaa33, 0xaa34, HB_Grapheme_Other},
+ {0xaa35, 0xaa36, HB_Grapheme_Extend},
+ {0xaa43, 0xaa43, HB_Grapheme_Extend},
+ {0xaa4c, 0xaa4c, HB_Grapheme_Extend},
+ {0xaa4d, 0xaa4d, HB_Grapheme_Other},
+ {0xac00, 0xac00, HB_Grapheme_LV},
+ {0xac01, 0xac1b, HB_Grapheme_LVT},
+ {0xac1c, 0xac1c, HB_Grapheme_LV},
+ {0xac1d, 0xac37, HB_Grapheme_LVT},
+ {0xac38, 0xac38, HB_Grapheme_LV},
+ {0xac39, 0xac53, HB_Grapheme_LVT},
+ {0xac54, 0xac54, HB_Grapheme_LV},
+ {0xac55, 0xac6f, HB_Grapheme_LVT},
+ {0xac70, 0xac70, HB_Grapheme_LV},
+ {0xac71, 0xac8b, HB_Grapheme_LVT},
+ {0xac8c, 0xac8c, HB_Grapheme_LV},
+ {0xac8d, 0xaca7, HB_Grapheme_LVT},
+ {0xaca8, 0xaca8, HB_Grapheme_LV},
+ {0xaca9, 0xacc3, HB_Grapheme_LVT},
+ {0xacc4, 0xacc4, HB_Grapheme_LV},
+ {0xacc5, 0xacdf, HB_Grapheme_LVT},
+ {0xace0, 0xace0, HB_Grapheme_LV},
+ {0xace1, 0xacfb, HB_Grapheme_LVT},
+ {0xacfc, 0xacfc, HB_Grapheme_LV},
+ {0xacfd, 0xad17, HB_Grapheme_LVT},
+ {0xad18, 0xad18, HB_Grapheme_LV},
+ {0xad19, 0xad33, HB_Grapheme_LVT},
+ {0xad34, 0xad34, HB_Grapheme_LV},
+ {0xad35, 0xad4f, HB_Grapheme_LVT},
+ {0xad50, 0xad50, HB_Grapheme_LV},
+ {0xad51, 0xad6b, HB_Grapheme_LVT},
+ {0xad6c, 0xad6c, HB_Grapheme_LV},
+ {0xad6d, 0xad87, HB_Grapheme_LVT},
+ {0xad88, 0xad88, HB_Grapheme_LV},
+ {0xad89, 0xada3, HB_Grapheme_LVT},
+ {0xada4, 0xada4, HB_Grapheme_LV},
+ {0xada5, 0xadbf, HB_Grapheme_LVT},
+ {0xadc0, 0xadc0, HB_Grapheme_LV},
+ {0xadc1, 0xaddb, HB_Grapheme_LVT},
+ {0xaddc, 0xaddc, HB_Grapheme_LV},
+ {0xaddd, 0xadf7, HB_Grapheme_LVT},
+ {0xadf8, 0xadf8, HB_Grapheme_LV},
+ {0xadf9, 0xae13, HB_Grapheme_LVT},
+ {0xae14, 0xae14, HB_Grapheme_LV},
+ {0xae15, 0xae2f, HB_Grapheme_LVT},
+ {0xae30, 0xae30, HB_Grapheme_LV},
+ {0xae31, 0xae4b, HB_Grapheme_LVT},
+ {0xae4c, 0xae4c, HB_Grapheme_LV},
+ {0xae4d, 0xae67, HB_Grapheme_LVT},
+ {0xae68, 0xae68, HB_Grapheme_LV},
+ {0xae69, 0xae83, HB_Grapheme_LVT},
+ {0xae84, 0xae84, HB_Grapheme_LV},
+ {0xae85, 0xae9f, HB_Grapheme_LVT},
+ {0xaea0, 0xaea0, HB_Grapheme_LV},
+ {0xaea1, 0xaebb, HB_Grapheme_LVT},
+ {0xaebc, 0xaebc, HB_Grapheme_LV},
+ {0xaebd, 0xaed7, HB_Grapheme_LVT},
+ {0xaed8, 0xaed8, HB_Grapheme_LV},
+ {0xaed9, 0xaef3, HB_Grapheme_LVT},
+ {0xaef4, 0xaef4, HB_Grapheme_LV},
+ {0xaef5, 0xaf0f, HB_Grapheme_LVT},
+ {0xaf10, 0xaf10, HB_Grapheme_LV},
+ {0xaf11, 0xaf2b, HB_Grapheme_LVT},
+ {0xaf2c, 0xaf2c, HB_Grapheme_LV},
+ {0xaf2d, 0xaf47, HB_Grapheme_LVT},
+ {0xaf48, 0xaf48, HB_Grapheme_LV},
+ {0xaf49, 0xaf63, HB_Grapheme_LVT},
+ {0xaf64, 0xaf64, HB_Grapheme_LV},
+ {0xaf65, 0xaf7f, HB_Grapheme_LVT},
+ {0xaf80, 0xaf80, HB_Grapheme_LV},
+ {0xaf81, 0xaf9b, HB_Grapheme_LVT},
+ {0xaf9c, 0xaf9c, HB_Grapheme_LV},
+ {0xaf9d, 0xafb7, HB_Grapheme_LVT},
+ {0xafb8, 0xafb8, HB_Grapheme_LV},
+ {0xafb9, 0xafd3, HB_Grapheme_LVT},
+ {0xafd4, 0xafd4, HB_Grapheme_LV},
+ {0xafd5, 0xafef, HB_Grapheme_LVT},
+ {0xaff0, 0xaff0, HB_Grapheme_LV},
+ {0xaff1, 0xb00b, HB_Grapheme_LVT},
+ {0xb00c, 0xb00c, HB_Grapheme_LV},
+ {0xb00d, 0xb027, HB_Grapheme_LVT},
+ {0xb028, 0xb028, HB_Grapheme_LV},
+ {0xb029, 0xb043, HB_Grapheme_LVT},
+ {0xb044, 0xb044, HB_Grapheme_LV},
+ {0xb045, 0xb05f, HB_Grapheme_LVT},
+ {0xb060, 0xb060, HB_Grapheme_LV},
+ {0xb061, 0xb07b, HB_Grapheme_LVT},
+ {0xb07c, 0xb07c, HB_Grapheme_LV},
+ {0xb07d, 0xb097, HB_Grapheme_LVT},
+ {0xb098, 0xb098, HB_Grapheme_LV},
+ {0xb099, 0xb0b3, HB_Grapheme_LVT},
+ {0xb0b4, 0xb0b4, HB_Grapheme_LV},
+ {0xb0b5, 0xb0cf, HB_Grapheme_LVT},
+ {0xb0d0, 0xb0d0, HB_Grapheme_LV},
+ {0xb0d1, 0xb0eb, HB_Grapheme_LVT},
+ {0xb0ec, 0xb0ec, HB_Grapheme_LV},
+ {0xb0ed, 0xb107, HB_Grapheme_LVT},
+ {0xb108, 0xb108, HB_Grapheme_LV},
+ {0xb109, 0xb123, HB_Grapheme_LVT},
+ {0xb124, 0xb124, HB_Grapheme_LV},
+ {0xb125, 0xb13f, HB_Grapheme_LVT},
+ {0xb140, 0xb140, HB_Grapheme_LV},
+ {0xb141, 0xb15b, HB_Grapheme_LVT},
+ {0xb15c, 0xb15c, HB_Grapheme_LV},
+ {0xb15d, 0xb177, HB_Grapheme_LVT},
+ {0xb178, 0xb178, HB_Grapheme_LV},
+ {0xb179, 0xb193, HB_Grapheme_LVT},
+ {0xb194, 0xb194, HB_Grapheme_LV},
+ {0xb195, 0xb1af, HB_Grapheme_LVT},
+ {0xb1b0, 0xb1b0, HB_Grapheme_LV},
+ {0xb1b1, 0xb1cb, HB_Grapheme_LVT},
+ {0xb1cc, 0xb1cc, HB_Grapheme_LV},
+ {0xb1cd, 0xb1e7, HB_Grapheme_LVT},
+ {0xb1e8, 0xb1e8, HB_Grapheme_LV},
+ {0xb1e9, 0xb203, HB_Grapheme_LVT},
+ {0xb204, 0xb204, HB_Grapheme_LV},
+ {0xb205, 0xb21f, HB_Grapheme_LVT},
+ {0xb220, 0xb220, HB_Grapheme_LV},
+ {0xb221, 0xb23b, HB_Grapheme_LVT},
+ {0xb23c, 0xb23c, HB_Grapheme_LV},
+ {0xb23d, 0xb257, HB_Grapheme_LVT},
+ {0xb258, 0xb258, HB_Grapheme_LV},
+ {0xb259, 0xb273, HB_Grapheme_LVT},
+ {0xb274, 0xb274, HB_Grapheme_LV},
+ {0xb275, 0xb28f, HB_Grapheme_LVT},
+ {0xb290, 0xb290, HB_Grapheme_LV},
+ {0xb291, 0xb2ab, HB_Grapheme_LVT},
+ {0xb2ac, 0xb2ac, HB_Grapheme_LV},
+ {0xb2ad, 0xb2c7, HB_Grapheme_LVT},
+ {0xb2c8, 0xb2c8, HB_Grapheme_LV},
+ {0xb2c9, 0xb2e3, HB_Grapheme_LVT},
+ {0xb2e4, 0xb2e4, HB_Grapheme_LV},
+ {0xb2e5, 0xb2ff, HB_Grapheme_LVT},
+ {0xb300, 0xb300, HB_Grapheme_LV},
+ {0xb301, 0xb31b, HB_Grapheme_LVT},
+ {0xb31c, 0xb31c, HB_Grapheme_LV},
+ {0xb31d, 0xb337, HB_Grapheme_LVT},
+ {0xb338, 0xb338, HB_Grapheme_LV},
+ {0xb339, 0xb353, HB_Grapheme_LVT},
+ {0xb354, 0xb354, HB_Grapheme_LV},
+ {0xb355, 0xb36f, HB_Grapheme_LVT},
+ {0xb370, 0xb370, HB_Grapheme_LV},
+ {0xb371, 0xb38b, HB_Grapheme_LVT},
+ {0xb38c, 0xb38c, HB_Grapheme_LV},
+ {0xb38d, 0xb3a7, HB_Grapheme_LVT},
+ {0xb3a8, 0xb3a8, HB_Grapheme_LV},
+ {0xb3a9, 0xb3c3, HB_Grapheme_LVT},
+ {0xb3c4, 0xb3c4, HB_Grapheme_LV},
+ {0xb3c5, 0xb3df, HB_Grapheme_LVT},
+ {0xb3e0, 0xb3e0, HB_Grapheme_LV},
+ {0xb3e1, 0xb3fb, HB_Grapheme_LVT},
+ {0xb3fc, 0xb3fc, HB_Grapheme_LV},
+ {0xb3fd, 0xb417, HB_Grapheme_LVT},
+ {0xb418, 0xb418, HB_Grapheme_LV},
+ {0xb419, 0xb433, HB_Grapheme_LVT},
+ {0xb434, 0xb434, HB_Grapheme_LV},
+ {0xb435, 0xb44f, HB_Grapheme_LVT},
+ {0xb450, 0xb450, HB_Grapheme_LV},
+ {0xb451, 0xb46b, HB_Grapheme_LVT},
+ {0xb46c, 0xb46c, HB_Grapheme_LV},
+ {0xb46d, 0xb487, HB_Grapheme_LVT},
+ {0xb488, 0xb488, HB_Grapheme_LV},
+ {0xb489, 0xb4a3, HB_Grapheme_LVT},
+ {0xb4a4, 0xb4a4, HB_Grapheme_LV},
+ {0xb4a5, 0xb4bf, HB_Grapheme_LVT},
+ {0xb4c0, 0xb4c0, HB_Grapheme_LV},
+ {0xb4c1, 0xb4db, HB_Grapheme_LVT},
+ {0xb4dc, 0xb4dc, HB_Grapheme_LV},
+ {0xb4dd, 0xb4f7, HB_Grapheme_LVT},
+ {0xb4f8, 0xb4f8, HB_Grapheme_LV},
+ {0xb4f9, 0xb513, HB_Grapheme_LVT},
+ {0xb514, 0xb514, HB_Grapheme_LV},
+ {0xb515, 0xb52f, HB_Grapheme_LVT},
+ {0xb530, 0xb530, HB_Grapheme_LV},
+ {0xb531, 0xb54b, HB_Grapheme_LVT},
+ {0xb54c, 0xb54c, HB_Grapheme_LV},
+ {0xb54d, 0xb567, HB_Grapheme_LVT},
+ {0xb568, 0xb568, HB_Grapheme_LV},
+ {0xb569, 0xb583, HB_Grapheme_LVT},
+ {0xb584, 0xb584, HB_Grapheme_LV},
+ {0xb585, 0xb59f, HB_Grapheme_LVT},
+ {0xb5a0, 0xb5a0, HB_Grapheme_LV},
+ {0xb5a1, 0xb5bb, HB_Grapheme_LVT},
+ {0xb5bc, 0xb5bc, HB_Grapheme_LV},
+ {0xb5bd, 0xb5d7, HB_Grapheme_LVT},
+ {0xb5d8, 0xb5d8, HB_Grapheme_LV},
+ {0xb5d9, 0xb5f3, HB_Grapheme_LVT},
+ {0xb5f4, 0xb5f4, HB_Grapheme_LV},
+ {0xb5f5, 0xb60f, HB_Grapheme_LVT},
+ {0xb610, 0xb610, HB_Grapheme_LV},
+ {0xb611, 0xb62b, HB_Grapheme_LVT},
+ {0xb62c, 0xb62c, HB_Grapheme_LV},
+ {0xb62d, 0xb647, HB_Grapheme_LVT},
+ {0xb648, 0xb648, HB_Grapheme_LV},
+ {0xb649, 0xb663, HB_Grapheme_LVT},
+ {0xb664, 0xb664, HB_Grapheme_LV},
+ {0xb665, 0xb67f, HB_Grapheme_LVT},
+ {0xb680, 0xb680, HB_Grapheme_LV},
+ {0xb681, 0xb69b, HB_Grapheme_LVT},
+ {0xb69c, 0xb69c, HB_Grapheme_LV},
+ {0xb69d, 0xb6b7, HB_Grapheme_LVT},
+ {0xb6b8, 0xb6b8, HB_Grapheme_LV},
+ {0xb6b9, 0xb6d3, HB_Grapheme_LVT},
+ {0xb6d4, 0xb6d4, HB_Grapheme_LV},
+ {0xb6d5, 0xb6ef, HB_Grapheme_LVT},
+ {0xb6f0, 0xb6f0, HB_Grapheme_LV},
+ {0xb6f1, 0xb70b, HB_Grapheme_LVT},
+ {0xb70c, 0xb70c, HB_Grapheme_LV},
+ {0xb70d, 0xb727, HB_Grapheme_LVT},
+ {0xb728, 0xb728, HB_Grapheme_LV},
+ {0xb729, 0xb743, HB_Grapheme_LVT},
+ {0xb744, 0xb744, HB_Grapheme_LV},
+ {0xb745, 0xb75f, HB_Grapheme_LVT},
+ {0xb760, 0xb760, HB_Grapheme_LV},
+ {0xb761, 0xb77b, HB_Grapheme_LVT},
+ {0xb77c, 0xb77c, HB_Grapheme_LV},
+ {0xb77d, 0xb797, HB_Grapheme_LVT},
+ {0xb798, 0xb798, HB_Grapheme_LV},
+ {0xb799, 0xb7b3, HB_Grapheme_LVT},
+ {0xb7b4, 0xb7b4, HB_Grapheme_LV},
+ {0xb7b5, 0xb7cf, HB_Grapheme_LVT},
+ {0xb7d0, 0xb7d0, HB_Grapheme_LV},
+ {0xb7d1, 0xb7eb, HB_Grapheme_LVT},
+ {0xb7ec, 0xb7ec, HB_Grapheme_LV},
+ {0xb7ed, 0xb807, HB_Grapheme_LVT},
+ {0xb808, 0xb808, HB_Grapheme_LV},
+ {0xb809, 0xb823, HB_Grapheme_LVT},
+ {0xb824, 0xb824, HB_Grapheme_LV},
+ {0xb825, 0xb83f, HB_Grapheme_LVT},
+ {0xb840, 0xb840, HB_Grapheme_LV},
+ {0xb841, 0xb85b, HB_Grapheme_LVT},
+ {0xb85c, 0xb85c, HB_Grapheme_LV},
+ {0xb85d, 0xb877, HB_Grapheme_LVT},
+ {0xb878, 0xb878, HB_Grapheme_LV},
+ {0xb879, 0xb893, HB_Grapheme_LVT},
+ {0xb894, 0xb894, HB_Grapheme_LV},
+ {0xb895, 0xb8af, HB_Grapheme_LVT},
+ {0xb8b0, 0xb8b0, HB_Grapheme_LV},
+ {0xb8b1, 0xb8cb, HB_Grapheme_LVT},
+ {0xb8cc, 0xb8cc, HB_Grapheme_LV},
+ {0xb8cd, 0xb8e7, HB_Grapheme_LVT},
+ {0xb8e8, 0xb8e8, HB_Grapheme_LV},
+ {0xb8e9, 0xb903, HB_Grapheme_LVT},
+ {0xb904, 0xb904, HB_Grapheme_LV},
+ {0xb905, 0xb91f, HB_Grapheme_LVT},
+ {0xb920, 0xb920, HB_Grapheme_LV},
+ {0xb921, 0xb93b, HB_Grapheme_LVT},
+ {0xb93c, 0xb93c, HB_Grapheme_LV},
+ {0xb93d, 0xb957, HB_Grapheme_LVT},
+ {0xb958, 0xb958, HB_Grapheme_LV},
+ {0xb959, 0xb973, HB_Grapheme_LVT},
+ {0xb974, 0xb974, HB_Grapheme_LV},
+ {0xb975, 0xb98f, HB_Grapheme_LVT},
+ {0xb990, 0xb990, HB_Grapheme_LV},
+ {0xb991, 0xb9ab, HB_Grapheme_LVT},
+ {0xb9ac, 0xb9ac, HB_Grapheme_LV},
+ {0xb9ad, 0xb9c7, HB_Grapheme_LVT},
+ {0xb9c8, 0xb9c8, HB_Grapheme_LV},
+ {0xb9c9, 0xb9e3, HB_Grapheme_LVT},
+ {0xb9e4, 0xb9e4, HB_Grapheme_LV},
+ {0xb9e5, 0xb9ff, HB_Grapheme_LVT},
+ {0xba00, 0xba00, HB_Grapheme_LV},
+ {0xba01, 0xba1b, HB_Grapheme_LVT},
+ {0xba1c, 0xba1c, HB_Grapheme_LV},
+ {0xba1d, 0xba37, HB_Grapheme_LVT},
+ {0xba38, 0xba38, HB_Grapheme_LV},
+ {0xba39, 0xba53, HB_Grapheme_LVT},
+ {0xba54, 0xba54, HB_Grapheme_LV},
+ {0xba55, 0xba6f, HB_Grapheme_LVT},
+ {0xba70, 0xba70, HB_Grapheme_LV},
+ {0xba71, 0xba8b, HB_Grapheme_LVT},
+ {0xba8c, 0xba8c, HB_Grapheme_LV},
+ {0xba8d, 0xbaa7, HB_Grapheme_LVT},
+ {0xbaa8, 0xbaa8, HB_Grapheme_LV},
+ {0xbaa9, 0xbac3, HB_Grapheme_LVT},
+ {0xbac4, 0xbac4, HB_Grapheme_LV},
+ {0xbac5, 0xbadf, HB_Grapheme_LVT},
+ {0xbae0, 0xbae0, HB_Grapheme_LV},
+ {0xbae1, 0xbafb, HB_Grapheme_LVT},
+ {0xbafc, 0xbafc, HB_Grapheme_LV},
+ {0xbafd, 0xbb17, HB_Grapheme_LVT},
+ {0xbb18, 0xbb18, HB_Grapheme_LV},
+ {0xbb19, 0xbb33, HB_Grapheme_LVT},
+ {0xbb34, 0xbb34, HB_Grapheme_LV},
+ {0xbb35, 0xbb4f, HB_Grapheme_LVT},
+ {0xbb50, 0xbb50, HB_Grapheme_LV},
+ {0xbb51, 0xbb6b, HB_Grapheme_LVT},
+ {0xbb6c, 0xbb6c, HB_Grapheme_LV},
+ {0xbb6d, 0xbb87, HB_Grapheme_LVT},
+ {0xbb88, 0xbb88, HB_Grapheme_LV},
+ {0xbb89, 0xbba3, HB_Grapheme_LVT},
+ {0xbba4, 0xbba4, HB_Grapheme_LV},
+ {0xbba5, 0xbbbf, HB_Grapheme_LVT},
+ {0xbbc0, 0xbbc0, HB_Grapheme_LV},
+ {0xbbc1, 0xbbdb, HB_Grapheme_LVT},
+ {0xbbdc, 0xbbdc, HB_Grapheme_LV},
+ {0xbbdd, 0xbbf7, HB_Grapheme_LVT},
+ {0xbbf8, 0xbbf8, HB_Grapheme_LV},
+ {0xbbf9, 0xbc13, HB_Grapheme_LVT},
+ {0xbc14, 0xbc14, HB_Grapheme_LV},
+ {0xbc15, 0xbc2f, HB_Grapheme_LVT},
+ {0xbc30, 0xbc30, HB_Grapheme_LV},
+ {0xbc31, 0xbc4b, HB_Grapheme_LVT},
+ {0xbc4c, 0xbc4c, HB_Grapheme_LV},
+ {0xbc4d, 0xbc67, HB_Grapheme_LVT},
+ {0xbc68, 0xbc68, HB_Grapheme_LV},
+ {0xbc69, 0xbc83, HB_Grapheme_LVT},
+ {0xbc84, 0xbc84, HB_Grapheme_LV},
+ {0xbc85, 0xbc9f, HB_Grapheme_LVT},
+ {0xbca0, 0xbca0, HB_Grapheme_LV},
+ {0xbca1, 0xbcbb, HB_Grapheme_LVT},
+ {0xbcbc, 0xbcbc, HB_Grapheme_LV},
+ {0xbcbd, 0xbcd7, HB_Grapheme_LVT},
+ {0xbcd8, 0xbcd8, HB_Grapheme_LV},
+ {0xbcd9, 0xbcf3, HB_Grapheme_LVT},
+ {0xbcf4, 0xbcf4, HB_Grapheme_LV},
+ {0xbcf5, 0xbd0f, HB_Grapheme_LVT},
+ {0xbd10, 0xbd10, HB_Grapheme_LV},
+ {0xbd11, 0xbd2b, HB_Grapheme_LVT},
+ {0xbd2c, 0xbd2c, HB_Grapheme_LV},
+ {0xbd2d, 0xbd47, HB_Grapheme_LVT},
+ {0xbd48, 0xbd48, HB_Grapheme_LV},
+ {0xbd49, 0xbd63, HB_Grapheme_LVT},
+ {0xbd64, 0xbd64, HB_Grapheme_LV},
+ {0xbd65, 0xbd7f, HB_Grapheme_LVT},
+ {0xbd80, 0xbd80, HB_Grapheme_LV},
+ {0xbd81, 0xbd9b, HB_Grapheme_LVT},
+ {0xbd9c, 0xbd9c, HB_Grapheme_LV},
+ {0xbd9d, 0xbdb7, HB_Grapheme_LVT},
+ {0xbdb8, 0xbdb8, HB_Grapheme_LV},
+ {0xbdb9, 0xbdd3, HB_Grapheme_LVT},
+ {0xbdd4, 0xbdd4, HB_Grapheme_LV},
+ {0xbdd5, 0xbdef, HB_Grapheme_LVT},
+ {0xbdf0, 0xbdf0, HB_Grapheme_LV},
+ {0xbdf1, 0xbe0b, HB_Grapheme_LVT},
+ {0xbe0c, 0xbe0c, HB_Grapheme_LV},
+ {0xbe0d, 0xbe27, HB_Grapheme_LVT},
+ {0xbe28, 0xbe28, HB_Grapheme_LV},
+ {0xbe29, 0xbe43, HB_Grapheme_LVT},
+ {0xbe44, 0xbe44, HB_Grapheme_LV},
+ {0xbe45, 0xbe5f, HB_Grapheme_LVT},
+ {0xbe60, 0xbe60, HB_Grapheme_LV},
+ {0xbe61, 0xbe7b, HB_Grapheme_LVT},
+ {0xbe7c, 0xbe7c, HB_Grapheme_LV},
+ {0xbe7d, 0xbe97, HB_Grapheme_LVT},
+ {0xbe98, 0xbe98, HB_Grapheme_LV},
+ {0xbe99, 0xbeb3, HB_Grapheme_LVT},
+ {0xbeb4, 0xbeb4, HB_Grapheme_LV},
+ {0xbeb5, 0xbecf, HB_Grapheme_LVT},
+ {0xbed0, 0xbed0, HB_Grapheme_LV},
+ {0xbed1, 0xbeeb, HB_Grapheme_LVT},
+ {0xbeec, 0xbeec, HB_Grapheme_LV},
+ {0xbeed, 0xbf07, HB_Grapheme_LVT},
+ {0xbf08, 0xbf08, HB_Grapheme_LV},
+ {0xbf09, 0xbf23, HB_Grapheme_LVT},
+ {0xbf24, 0xbf24, HB_Grapheme_LV},
+ {0xbf25, 0xbf3f, HB_Grapheme_LVT},
+ {0xbf40, 0xbf40, HB_Grapheme_LV},
+ {0xbf41, 0xbf5b, HB_Grapheme_LVT},
+ {0xbf5c, 0xbf5c, HB_Grapheme_LV},
+ {0xbf5d, 0xbf77, HB_Grapheme_LVT},
+ {0xbf78, 0xbf78, HB_Grapheme_LV},
+ {0xbf79, 0xbf93, HB_Grapheme_LVT},
+ {0xbf94, 0xbf94, HB_Grapheme_LV},
+ {0xbf95, 0xbfaf, HB_Grapheme_LVT},
+ {0xbfb0, 0xbfb0, HB_Grapheme_LV},
+ {0xbfb1, 0xbfcb, HB_Grapheme_LVT},
+ {0xbfcc, 0xbfcc, HB_Grapheme_LV},
+ {0xbfcd, 0xbfe7, HB_Grapheme_LVT},
+ {0xbfe8, 0xbfe8, HB_Grapheme_LV},
+ {0xbfe9, 0xc003, HB_Grapheme_LVT},
+ {0xc004, 0xc004, HB_Grapheme_LV},
+ {0xc005, 0xc01f, HB_Grapheme_LVT},
+ {0xc020, 0xc020, HB_Grapheme_LV},
+ {0xc021, 0xc03b, HB_Grapheme_LVT},
+ {0xc03c, 0xc03c, HB_Grapheme_LV},
+ {0xc03d, 0xc057, HB_Grapheme_LVT},
+ {0xc058, 0xc058, HB_Grapheme_LV},
+ {0xc059, 0xc073, HB_Grapheme_LVT},
+ {0xc074, 0xc074, HB_Grapheme_LV},
+ {0xc075, 0xc08f, HB_Grapheme_LVT},
+ {0xc090, 0xc090, HB_Grapheme_LV},
+ {0xc091, 0xc0ab, HB_Grapheme_LVT},
+ {0xc0ac, 0xc0ac, HB_Grapheme_LV},
+ {0xc0ad, 0xc0c7, HB_Grapheme_LVT},
+ {0xc0c8, 0xc0c8, HB_Grapheme_LV},
+ {0xc0c9, 0xc0e3, HB_Grapheme_LVT},
+ {0xc0e4, 0xc0e4, HB_Grapheme_LV},
+ {0xc0e5, 0xc0ff, HB_Grapheme_LVT},
+ {0xc100, 0xc100, HB_Grapheme_LV},
+ {0xc101, 0xc11b, HB_Grapheme_LVT},
+ {0xc11c, 0xc11c, HB_Grapheme_LV},
+ {0xc11d, 0xc137, HB_Grapheme_LVT},
+ {0xc138, 0xc138, HB_Grapheme_LV},
+ {0xc139, 0xc153, HB_Grapheme_LVT},
+ {0xc154, 0xc154, HB_Grapheme_LV},
+ {0xc155, 0xc16f, HB_Grapheme_LVT},
+ {0xc170, 0xc170, HB_Grapheme_LV},
+ {0xc171, 0xc18b, HB_Grapheme_LVT},
+ {0xc18c, 0xc18c, HB_Grapheme_LV},
+ {0xc18d, 0xc1a7, HB_Grapheme_LVT},
+ {0xc1a8, 0xc1a8, HB_Grapheme_LV},
+ {0xc1a9, 0xc1c3, HB_Grapheme_LVT},
+ {0xc1c4, 0xc1c4, HB_Grapheme_LV},
+ {0xc1c5, 0xc1df, HB_Grapheme_LVT},
+ {0xc1e0, 0xc1e0, HB_Grapheme_LV},
+ {0xc1e1, 0xc1fb, HB_Grapheme_LVT},
+ {0xc1fc, 0xc1fc, HB_Grapheme_LV},
+ {0xc1fd, 0xc217, HB_Grapheme_LVT},
+ {0xc218, 0xc218, HB_Grapheme_LV},
+ {0xc219, 0xc233, HB_Grapheme_LVT},
+ {0xc234, 0xc234, HB_Grapheme_LV},
+ {0xc235, 0xc24f, HB_Grapheme_LVT},
+ {0xc250, 0xc250, HB_Grapheme_LV},
+ {0xc251, 0xc26b, HB_Grapheme_LVT},
+ {0xc26c, 0xc26c, HB_Grapheme_LV},
+ {0xc26d, 0xc287, HB_Grapheme_LVT},
+ {0xc288, 0xc288, HB_Grapheme_LV},
+ {0xc289, 0xc2a3, HB_Grapheme_LVT},
+ {0xc2a4, 0xc2a4, HB_Grapheme_LV},
+ {0xc2a5, 0xc2bf, HB_Grapheme_LVT},
+ {0xc2c0, 0xc2c0, HB_Grapheme_LV},
+ {0xc2c1, 0xc2db, HB_Grapheme_LVT},
+ {0xc2dc, 0xc2dc, HB_Grapheme_LV},
+ {0xc2dd, 0xc2f7, HB_Grapheme_LVT},
+ {0xc2f8, 0xc2f8, HB_Grapheme_LV},
+ {0xc2f9, 0xc313, HB_Grapheme_LVT},
+ {0xc314, 0xc314, HB_Grapheme_LV},
+ {0xc315, 0xc32f, HB_Grapheme_LVT},
+ {0xc330, 0xc330, HB_Grapheme_LV},
+ {0xc331, 0xc34b, HB_Grapheme_LVT},
+ {0xc34c, 0xc34c, HB_Grapheme_LV},
+ {0xc34d, 0xc367, HB_Grapheme_LVT},
+ {0xc368, 0xc368, HB_Grapheme_LV},
+ {0xc369, 0xc383, HB_Grapheme_LVT},
+ {0xc384, 0xc384, HB_Grapheme_LV},
+ {0xc385, 0xc39f, HB_Grapheme_LVT},
+ {0xc3a0, 0xc3a0, HB_Grapheme_LV},
+ {0xc3a1, 0xc3bb, HB_Grapheme_LVT},
+ {0xc3bc, 0xc3bc, HB_Grapheme_LV},
+ {0xc3bd, 0xc3d7, HB_Grapheme_LVT},
+ {0xc3d8, 0xc3d8, HB_Grapheme_LV},
+ {0xc3d9, 0xc3f3, HB_Grapheme_LVT},
+ {0xc3f4, 0xc3f4, HB_Grapheme_LV},
+ {0xc3f5, 0xc40f, HB_Grapheme_LVT},
+ {0xc410, 0xc410, HB_Grapheme_LV},
+ {0xc411, 0xc42b, HB_Grapheme_LVT},
+ {0xc42c, 0xc42c, HB_Grapheme_LV},
+ {0xc42d, 0xc447, HB_Grapheme_LVT},
+ {0xc448, 0xc448, HB_Grapheme_LV},
+ {0xc449, 0xc463, HB_Grapheme_LVT},
+ {0xc464, 0xc464, HB_Grapheme_LV},
+ {0xc465, 0xc47f, HB_Grapheme_LVT},
+ {0xc480, 0xc480, HB_Grapheme_LV},
+ {0xc481, 0xc49b, HB_Grapheme_LVT},
+ {0xc49c, 0xc49c, HB_Grapheme_LV},
+ {0xc49d, 0xc4b7, HB_Grapheme_LVT},
+ {0xc4b8, 0xc4b8, HB_Grapheme_LV},
+ {0xc4b9, 0xc4d3, HB_Grapheme_LVT},
+ {0xc4d4, 0xc4d4, HB_Grapheme_LV},
+ {0xc4d5, 0xc4ef, HB_Grapheme_LVT},
+ {0xc4f0, 0xc4f0, HB_Grapheme_LV},
+ {0xc4f1, 0xc50b, HB_Grapheme_LVT},
+ {0xc50c, 0xc50c, HB_Grapheme_LV},
+ {0xc50d, 0xc527, HB_Grapheme_LVT},
+ {0xc528, 0xc528, HB_Grapheme_LV},
+ {0xc529, 0xc543, HB_Grapheme_LVT},
+ {0xc544, 0xc544, HB_Grapheme_LV},
+ {0xc545, 0xc55f, HB_Grapheme_LVT},
+ {0xc560, 0xc560, HB_Grapheme_LV},
+ {0xc561, 0xc57b, HB_Grapheme_LVT},
+ {0xc57c, 0xc57c, HB_Grapheme_LV},
+ {0xc57d, 0xc597, HB_Grapheme_LVT},
+ {0xc598, 0xc598, HB_Grapheme_LV},
+ {0xc599, 0xc5b3, HB_Grapheme_LVT},
+ {0xc5b4, 0xc5b4, HB_Grapheme_LV},
+ {0xc5b5, 0xc5cf, HB_Grapheme_LVT},
+ {0xc5d0, 0xc5d0, HB_Grapheme_LV},
+ {0xc5d1, 0xc5eb, HB_Grapheme_LVT},
+ {0xc5ec, 0xc5ec, HB_Grapheme_LV},
+ {0xc5ed, 0xc607, HB_Grapheme_LVT},
+ {0xc608, 0xc608, HB_Grapheme_LV},
+ {0xc609, 0xc623, HB_Grapheme_LVT},
+ {0xc624, 0xc624, HB_Grapheme_LV},
+ {0xc625, 0xc63f, HB_Grapheme_LVT},
+ {0xc640, 0xc640, HB_Grapheme_LV},
+ {0xc641, 0xc65b, HB_Grapheme_LVT},
+ {0xc65c, 0xc65c, HB_Grapheme_LV},
+ {0xc65d, 0xc677, HB_Grapheme_LVT},
+ {0xc678, 0xc678, HB_Grapheme_LV},
+ {0xc679, 0xc693, HB_Grapheme_LVT},
+ {0xc694, 0xc694, HB_Grapheme_LV},
+ {0xc695, 0xc6af, HB_Grapheme_LVT},
+ {0xc6b0, 0xc6b0, HB_Grapheme_LV},
+ {0xc6b1, 0xc6cb, HB_Grapheme_LVT},
+ {0xc6cc, 0xc6cc, HB_Grapheme_LV},
+ {0xc6cd, 0xc6e7, HB_Grapheme_LVT},
+ {0xc6e8, 0xc6e8, HB_Grapheme_LV},
+ {0xc6e9, 0xc703, HB_Grapheme_LVT},
+ {0xc704, 0xc704, HB_Grapheme_LV},
+ {0xc705, 0xc71f, HB_Grapheme_LVT},
+ {0xc720, 0xc720, HB_Grapheme_LV},
+ {0xc721, 0xc73b, HB_Grapheme_LVT},
+ {0xc73c, 0xc73c, HB_Grapheme_LV},
+ {0xc73d, 0xc757, HB_Grapheme_LVT},
+ {0xc758, 0xc758, HB_Grapheme_LV},
+ {0xc759, 0xc773, HB_Grapheme_LVT},
+ {0xc774, 0xc774, HB_Grapheme_LV},
+ {0xc775, 0xc78f, HB_Grapheme_LVT},
+ {0xc790, 0xc790, HB_Grapheme_LV},
+ {0xc791, 0xc7ab, HB_Grapheme_LVT},
+ {0xc7ac, 0xc7ac, HB_Grapheme_LV},
+ {0xc7ad, 0xc7c7, HB_Grapheme_LVT},
+ {0xc7c8, 0xc7c8, HB_Grapheme_LV},
+ {0xc7c9, 0xc7e3, HB_Grapheme_LVT},
+ {0xc7e4, 0xc7e4, HB_Grapheme_LV},
+ {0xc7e5, 0xc7ff, HB_Grapheme_LVT},
+ {0xc800, 0xc800, HB_Grapheme_LV},
+ {0xc801, 0xc81b, HB_Grapheme_LVT},
+ {0xc81c, 0xc81c, HB_Grapheme_LV},
+ {0xc81d, 0xc837, HB_Grapheme_LVT},
+ {0xc838, 0xc838, HB_Grapheme_LV},
+ {0xc839, 0xc853, HB_Grapheme_LVT},
+ {0xc854, 0xc854, HB_Grapheme_LV},
+ {0xc855, 0xc86f, HB_Grapheme_LVT},
+ {0xc870, 0xc870, HB_Grapheme_LV},
+ {0xc871, 0xc88b, HB_Grapheme_LVT},
+ {0xc88c, 0xc88c, HB_Grapheme_LV},
+ {0xc88d, 0xc8a7, HB_Grapheme_LVT},
+ {0xc8a8, 0xc8a8, HB_Grapheme_LV},
+ {0xc8a9, 0xc8c3, HB_Grapheme_LVT},
+ {0xc8c4, 0xc8c4, HB_Grapheme_LV},
+ {0xc8c5, 0xc8df, HB_Grapheme_LVT},
+ {0xc8e0, 0xc8e0, HB_Grapheme_LV},
+ {0xc8e1, 0xc8fb, HB_Grapheme_LVT},
+ {0xc8fc, 0xc8fc, HB_Grapheme_LV},
+ {0xc8fd, 0xc917, HB_Grapheme_LVT},
+ {0xc918, 0xc918, HB_Grapheme_LV},
+ {0xc919, 0xc933, HB_Grapheme_LVT},
+ {0xc934, 0xc934, HB_Grapheme_LV},
+ {0xc935, 0xc94f, HB_Grapheme_LVT},
+ {0xc950, 0xc950, HB_Grapheme_LV},
+ {0xc951, 0xc96b, HB_Grapheme_LVT},
+ {0xc96c, 0xc96c, HB_Grapheme_LV},
+ {0xc96d, 0xc987, HB_Grapheme_LVT},
+ {0xc988, 0xc988, HB_Grapheme_LV},
+ {0xc989, 0xc9a3, HB_Grapheme_LVT},
+ {0xc9a4, 0xc9a4, HB_Grapheme_LV},
+ {0xc9a5, 0xc9bf, HB_Grapheme_LVT},
+ {0xc9c0, 0xc9c0, HB_Grapheme_LV},
+ {0xc9c1, 0xc9db, HB_Grapheme_LVT},
+ {0xc9dc, 0xc9dc, HB_Grapheme_LV},
+ {0xc9dd, 0xc9f7, HB_Grapheme_LVT},
+ {0xc9f8, 0xc9f8, HB_Grapheme_LV},
+ {0xc9f9, 0xca13, HB_Grapheme_LVT},
+ {0xca14, 0xca14, HB_Grapheme_LV},
+ {0xca15, 0xca2f, HB_Grapheme_LVT},
+ {0xca30, 0xca30, HB_Grapheme_LV},
+ {0xca31, 0xca4b, HB_Grapheme_LVT},
+ {0xca4c, 0xca4c, HB_Grapheme_LV},
+ {0xca4d, 0xca67, HB_Grapheme_LVT},
+ {0xca68, 0xca68, HB_Grapheme_LV},
+ {0xca69, 0xca83, HB_Grapheme_LVT},
+ {0xca84, 0xca84, HB_Grapheme_LV},
+ {0xca85, 0xca9f, HB_Grapheme_LVT},
+ {0xcaa0, 0xcaa0, HB_Grapheme_LV},
+ {0xcaa1, 0xcabb, HB_Grapheme_LVT},
+ {0xcabc, 0xcabc, HB_Grapheme_LV},
+ {0xcabd, 0xcad7, HB_Grapheme_LVT},
+ {0xcad8, 0xcad8, HB_Grapheme_LV},
+ {0xcad9, 0xcaf3, HB_Grapheme_LVT},
+ {0xcaf4, 0xcaf4, HB_Grapheme_LV},
+ {0xcaf5, 0xcb0f, HB_Grapheme_LVT},
+ {0xcb10, 0xcb10, HB_Grapheme_LV},
+ {0xcb11, 0xcb2b, HB_Grapheme_LVT},
+ {0xcb2c, 0xcb2c, HB_Grapheme_LV},
+ {0xcb2d, 0xcb47, HB_Grapheme_LVT},
+ {0xcb48, 0xcb48, HB_Grapheme_LV},
+ {0xcb49, 0xcb63, HB_Grapheme_LVT},
+ {0xcb64, 0xcb64, HB_Grapheme_LV},
+ {0xcb65, 0xcb7f, HB_Grapheme_LVT},
+ {0xcb80, 0xcb80, HB_Grapheme_LV},
+ {0xcb81, 0xcb9b, HB_Grapheme_LVT},
+ {0xcb9c, 0xcb9c, HB_Grapheme_LV},
+ {0xcb9d, 0xcbb7, HB_Grapheme_LVT},
+ {0xcbb8, 0xcbb8, HB_Grapheme_LV},
+ {0xcbb9, 0xcbd3, HB_Grapheme_LVT},
+ {0xcbd4, 0xcbd4, HB_Grapheme_LV},
+ {0xcbd5, 0xcbef, HB_Grapheme_LVT},
+ {0xcbf0, 0xcbf0, HB_Grapheme_LV},
+ {0xcbf1, 0xcc0b, HB_Grapheme_LVT},
+ {0xcc0c, 0xcc0c, HB_Grapheme_LV},
+ {0xcc0d, 0xcc27, HB_Grapheme_LVT},
+ {0xcc28, 0xcc28, HB_Grapheme_LV},
+ {0xcc29, 0xcc43, HB_Grapheme_LVT},
+ {0xcc44, 0xcc44, HB_Grapheme_LV},
+ {0xcc45, 0xcc5f, HB_Grapheme_LVT},
+ {0xcc60, 0xcc60, HB_Grapheme_LV},
+ {0xcc61, 0xcc7b, HB_Grapheme_LVT},
+ {0xcc7c, 0xcc7c, HB_Grapheme_LV},
+ {0xcc7d, 0xcc97, HB_Grapheme_LVT},
+ {0xcc98, 0xcc98, HB_Grapheme_LV},
+ {0xcc99, 0xccb3, HB_Grapheme_LVT},
+ {0xccb4, 0xccb4, HB_Grapheme_LV},
+ {0xccb5, 0xcccf, HB_Grapheme_LVT},
+ {0xccd0, 0xccd0, HB_Grapheme_LV},
+ {0xccd1, 0xcceb, HB_Grapheme_LVT},
+ {0xccec, 0xccec, HB_Grapheme_LV},
+ {0xcced, 0xcd07, HB_Grapheme_LVT},
+ {0xcd08, 0xcd08, HB_Grapheme_LV},
+ {0xcd09, 0xcd23, HB_Grapheme_LVT},
+ {0xcd24, 0xcd24, HB_Grapheme_LV},
+ {0xcd25, 0xcd3f, HB_Grapheme_LVT},
+ {0xcd40, 0xcd40, HB_Grapheme_LV},
+ {0xcd41, 0xcd5b, HB_Grapheme_LVT},
+ {0xcd5c, 0xcd5c, HB_Grapheme_LV},
+ {0xcd5d, 0xcd77, HB_Grapheme_LVT},
+ {0xcd78, 0xcd78, HB_Grapheme_LV},
+ {0xcd79, 0xcd93, HB_Grapheme_LVT},
+ {0xcd94, 0xcd94, HB_Grapheme_LV},
+ {0xcd95, 0xcdaf, HB_Grapheme_LVT},
+ {0xcdb0, 0xcdb0, HB_Grapheme_LV},
+ {0xcdb1, 0xcdcb, HB_Grapheme_LVT},
+ {0xcdcc, 0xcdcc, HB_Grapheme_LV},
+ {0xcdcd, 0xcde7, HB_Grapheme_LVT},
+ {0xcde8, 0xcde8, HB_Grapheme_LV},
+ {0xcde9, 0xce03, HB_Grapheme_LVT},
+ {0xce04, 0xce04, HB_Grapheme_LV},
+ {0xce05, 0xce1f, HB_Grapheme_LVT},
+ {0xce20, 0xce20, HB_Grapheme_LV},
+ {0xce21, 0xce3b, HB_Grapheme_LVT},
+ {0xce3c, 0xce3c, HB_Grapheme_LV},
+ {0xce3d, 0xce57, HB_Grapheme_LVT},
+ {0xce58, 0xce58, HB_Grapheme_LV},
+ {0xce59, 0xce73, HB_Grapheme_LVT},
+ {0xce74, 0xce74, HB_Grapheme_LV},
+ {0xce75, 0xce8f, HB_Grapheme_LVT},
+ {0xce90, 0xce90, HB_Grapheme_LV},
+ {0xce91, 0xceab, HB_Grapheme_LVT},
+ {0xceac, 0xceac, HB_Grapheme_LV},
+ {0xcead, 0xcec7, HB_Grapheme_LVT},
+ {0xcec8, 0xcec8, HB_Grapheme_LV},
+ {0xcec9, 0xcee3, HB_Grapheme_LVT},
+ {0xcee4, 0xcee4, HB_Grapheme_LV},
+ {0xcee5, 0xceff, HB_Grapheme_LVT},
+ {0xcf00, 0xcf00, HB_Grapheme_LV},
+ {0xcf01, 0xcf1b, HB_Grapheme_LVT},
+ {0xcf1c, 0xcf1c, HB_Grapheme_LV},
+ {0xcf1d, 0xcf37, HB_Grapheme_LVT},
+ {0xcf38, 0xcf38, HB_Grapheme_LV},
+ {0xcf39, 0xcf53, HB_Grapheme_LVT},
+ {0xcf54, 0xcf54, HB_Grapheme_LV},
+ {0xcf55, 0xcf6f, HB_Grapheme_LVT},
+ {0xcf70, 0xcf70, HB_Grapheme_LV},
+ {0xcf71, 0xcf8b, HB_Grapheme_LVT},
+ {0xcf8c, 0xcf8c, HB_Grapheme_LV},
+ {0xcf8d, 0xcfa7, HB_Grapheme_LVT},
+ {0xcfa8, 0xcfa8, HB_Grapheme_LV},
+ {0xcfa9, 0xcfc3, HB_Grapheme_LVT},
+ {0xcfc4, 0xcfc4, HB_Grapheme_LV},
+ {0xcfc5, 0xcfdf, HB_Grapheme_LVT},
+ {0xcfe0, 0xcfe0, HB_Grapheme_LV},
+ {0xcfe1, 0xcffb, HB_Grapheme_LVT},
+ {0xcffc, 0xcffc, HB_Grapheme_LV},
+ {0xcffd, 0xd017, HB_Grapheme_LVT},
+ {0xd018, 0xd018, HB_Grapheme_LV},
+ {0xd019, 0xd033, HB_Grapheme_LVT},
+ {0xd034, 0xd034, HB_Grapheme_LV},
+ {0xd035, 0xd04f, HB_Grapheme_LVT},
+ {0xd050, 0xd050, HB_Grapheme_LV},
+ {0xd051, 0xd06b, HB_Grapheme_LVT},
+ {0xd06c, 0xd06c, HB_Grapheme_LV},
+ {0xd06d, 0xd087, HB_Grapheme_LVT},
+ {0xd088, 0xd088, HB_Grapheme_LV},
+ {0xd089, 0xd0a3, HB_Grapheme_LVT},
+ {0xd0a4, 0xd0a4, HB_Grapheme_LV},
+ {0xd0a5, 0xd0bf, HB_Grapheme_LVT},
+ {0xd0c0, 0xd0c0, HB_Grapheme_LV},
+ {0xd0c1, 0xd0db, HB_Grapheme_LVT},
+ {0xd0dc, 0xd0dc, HB_Grapheme_LV},
+ {0xd0dd, 0xd0f7, HB_Grapheme_LVT},
+ {0xd0f8, 0xd0f8, HB_Grapheme_LV},
+ {0xd0f9, 0xd113, HB_Grapheme_LVT},
+ {0xd114, 0xd114, HB_Grapheme_LV},
+ {0xd115, 0xd12f, HB_Grapheme_LVT},
+ {0xd130, 0xd130, HB_Grapheme_LV},
+ {0xd131, 0xd14b, HB_Grapheme_LVT},
+ {0xd14c, 0xd14c, HB_Grapheme_LV},
+ {0xd14d, 0xd167, HB_Grapheme_LVT},
+ {0xd168, 0xd168, HB_Grapheme_LV},
+ {0xd169, 0xd183, HB_Grapheme_LVT},
+ {0xd184, 0xd184, HB_Grapheme_LV},
+ {0xd185, 0xd19f, HB_Grapheme_LVT},
+ {0xd1a0, 0xd1a0, HB_Grapheme_LV},
+ {0xd1a1, 0xd1bb, HB_Grapheme_LVT},
+ {0xd1bc, 0xd1bc, HB_Grapheme_LV},
+ {0xd1bd, 0xd1d7, HB_Grapheme_LVT},
+ {0xd1d8, 0xd1d8, HB_Grapheme_LV},
+ {0xd1d9, 0xd1f3, HB_Grapheme_LVT},
+ {0xd1f4, 0xd1f4, HB_Grapheme_LV},
+ {0xd1f5, 0xd20f, HB_Grapheme_LVT},
+ {0xd210, 0xd210, HB_Grapheme_LV},
+ {0xd211, 0xd22b, HB_Grapheme_LVT},
+ {0xd22c, 0xd22c, HB_Grapheme_LV},
+ {0xd22d, 0xd247, HB_Grapheme_LVT},
+ {0xd248, 0xd248, HB_Grapheme_LV},
+ {0xd249, 0xd263, HB_Grapheme_LVT},
+ {0xd264, 0xd264, HB_Grapheme_LV},
+ {0xd265, 0xd27f, HB_Grapheme_LVT},
+ {0xd280, 0xd280, HB_Grapheme_LV},
+ {0xd281, 0xd29b, HB_Grapheme_LVT},
+ {0xd29c, 0xd29c, HB_Grapheme_LV},
+ {0xd29d, 0xd2b7, HB_Grapheme_LVT},
+ {0xd2b8, 0xd2b8, HB_Grapheme_LV},
+ {0xd2b9, 0xd2d3, HB_Grapheme_LVT},
+ {0xd2d4, 0xd2d4, HB_Grapheme_LV},
+ {0xd2d5, 0xd2ef, HB_Grapheme_LVT},
+ {0xd2f0, 0xd2f0, HB_Grapheme_LV},
+ {0xd2f1, 0xd30b, HB_Grapheme_LVT},
+ {0xd30c, 0xd30c, HB_Grapheme_LV},
+ {0xd30d, 0xd327, HB_Grapheme_LVT},
+ {0xd328, 0xd328, HB_Grapheme_LV},
+ {0xd329, 0xd343, HB_Grapheme_LVT},
+ {0xd344, 0xd344, HB_Grapheme_LV},
+ {0xd345, 0xd35f, HB_Grapheme_LVT},
+ {0xd360, 0xd360, HB_Grapheme_LV},
+ {0xd361, 0xd37b, HB_Grapheme_LVT},
+ {0xd37c, 0xd37c, HB_Grapheme_LV},
+ {0xd37d, 0xd397, HB_Grapheme_LVT},
+ {0xd398, 0xd398, HB_Grapheme_LV},
+ {0xd399, 0xd3b3, HB_Grapheme_LVT},
+ {0xd3b4, 0xd3b4, HB_Grapheme_LV},
+ {0xd3b5, 0xd3cf, HB_Grapheme_LVT},
+ {0xd3d0, 0xd3d0, HB_Grapheme_LV},
+ {0xd3d1, 0xd3eb, HB_Grapheme_LVT},
+ {0xd3ec, 0xd3ec, HB_Grapheme_LV},
+ {0xd3ed, 0xd407, HB_Grapheme_LVT},
+ {0xd408, 0xd408, HB_Grapheme_LV},
+ {0xd409, 0xd423, HB_Grapheme_LVT},
+ {0xd424, 0xd424, HB_Grapheme_LV},
+ {0xd425, 0xd43f, HB_Grapheme_LVT},
+ {0xd440, 0xd440, HB_Grapheme_LV},
+ {0xd441, 0xd45b, HB_Grapheme_LVT},
+ {0xd45c, 0xd45c, HB_Grapheme_LV},
+ {0xd45d, 0xd477, HB_Grapheme_LVT},
+ {0xd478, 0xd478, HB_Grapheme_LV},
+ {0xd479, 0xd493, HB_Grapheme_LVT},
+ {0xd494, 0xd494, HB_Grapheme_LV},
+ {0xd495, 0xd4af, HB_Grapheme_LVT},
+ {0xd4b0, 0xd4b0, HB_Grapheme_LV},
+ {0xd4b1, 0xd4cb, HB_Grapheme_LVT},
+ {0xd4cc, 0xd4cc, HB_Grapheme_LV},
+ {0xd4cd, 0xd4e7, HB_Grapheme_LVT},
+ {0xd4e8, 0xd4e8, HB_Grapheme_LV},
+ {0xd4e9, 0xd503, HB_Grapheme_LVT},
+ {0xd504, 0xd504, HB_Grapheme_LV},
+ {0xd505, 0xd51f, HB_Grapheme_LVT},
+ {0xd520, 0xd520, HB_Grapheme_LV},
+ {0xd521, 0xd53b, HB_Grapheme_LVT},
+ {0xd53c, 0xd53c, HB_Grapheme_LV},
+ {0xd53d, 0xd557, HB_Grapheme_LVT},
+ {0xd558, 0xd558, HB_Grapheme_LV},
+ {0xd559, 0xd573, HB_Grapheme_LVT},
+ {0xd574, 0xd574, HB_Grapheme_LV},
+ {0xd575, 0xd58f, HB_Grapheme_LVT},
+ {0xd590, 0xd590, HB_Grapheme_LV},
+ {0xd591, 0xd5ab, HB_Grapheme_LVT},
+ {0xd5ac, 0xd5ac, HB_Grapheme_LV},
+ {0xd5ad, 0xd5c7, HB_Grapheme_LVT},
+ {0xd5c8, 0xd5c8, HB_Grapheme_LV},
+ {0xd5c9, 0xd5e3, HB_Grapheme_LVT},
+ {0xd5e4, 0xd5e4, HB_Grapheme_LV},
+ {0xd5e5, 0xd5ff, HB_Grapheme_LVT},
+ {0xd600, 0xd600, HB_Grapheme_LV},
+ {0xd601, 0xd61b, HB_Grapheme_LVT},
+ {0xd61c, 0xd61c, HB_Grapheme_LV},
+ {0xd61d, 0xd637, HB_Grapheme_LVT},
+ {0xd638, 0xd638, HB_Grapheme_LV},
+ {0xd639, 0xd653, HB_Grapheme_LVT},
+ {0xd654, 0xd654, HB_Grapheme_LV},
+ {0xd655, 0xd66f, HB_Grapheme_LVT},
+ {0xd670, 0xd670, HB_Grapheme_LV},
+ {0xd671, 0xd68b, HB_Grapheme_LVT},
+ {0xd68c, 0xd68c, HB_Grapheme_LV},
+ {0xd68d, 0xd6a7, HB_Grapheme_LVT},
+ {0xd6a8, 0xd6a8, HB_Grapheme_LV},
+ {0xd6a9, 0xd6c3, HB_Grapheme_LVT},
+ {0xd6c4, 0xd6c4, HB_Grapheme_LV},
+ {0xd6c5, 0xd6df, HB_Grapheme_LVT},
+ {0xd6e0, 0xd6e0, HB_Grapheme_LV},
+ {0xd6e1, 0xd6fb, HB_Grapheme_LVT},
+ {0xd6fc, 0xd6fc, HB_Grapheme_LV},
+ {0xd6fd, 0xd717, HB_Grapheme_LVT},
+ {0xd718, 0xd718, HB_Grapheme_LV},
+ {0xd719, 0xd733, HB_Grapheme_LVT},
+ {0xd734, 0xd734, HB_Grapheme_LV},
+ {0xd735, 0xd74f, HB_Grapheme_LVT},
+ {0xd750, 0xd750, HB_Grapheme_LV},
+ {0xd751, 0xd76b, HB_Grapheme_LVT},
+ {0xd76c, 0xd76c, HB_Grapheme_LV},
+ {0xd76d, 0xd787, HB_Grapheme_LVT},
+ {0xd788, 0xd788, HB_Grapheme_LV},
+ {0xd789, 0xd7a3, HB_Grapheme_LVT},
+ {0xfb1e, 0xfb1e, HB_Grapheme_Extend},
+ {0xfe00, 0xfe0f, HB_Grapheme_Extend},
+ {0xfe20, 0xfe26, HB_Grapheme_Extend},
+ {0xfeff, 0xfeff, HB_Grapheme_Control},
+ {0xff9e, 0xff9f, HB_Grapheme_Extend},
+ {0xfff9, 0xfffb, HB_Grapheme_Control},
+ {0x101fd, 0x101fd, HB_Grapheme_Extend},
+ {0x10a01, 0x10a03, HB_Grapheme_Extend},
+ {0x10a05, 0x10a06, HB_Grapheme_Extend},
+ {0x10a0c, 0x10a0f, HB_Grapheme_Extend},
+ {0x10a38, 0x10a3a, HB_Grapheme_Extend},
+ {0x10a3f, 0x10a3f, HB_Grapheme_Extend},
+ {0x1d165, 0x1d165, HB_Grapheme_Extend},
+ {0x1d166, 0x1d166, HB_Grapheme_Other},
+ {0x1d167, 0x1d169, HB_Grapheme_Extend},
+ {0x1d16d, 0x1d16d, HB_Grapheme_Other},
+ {0x1d16e, 0x1d172, HB_Grapheme_Extend},
+ {0x1d173, 0x1d17a, HB_Grapheme_Control},
+ {0x1d17b, 0x1d182, HB_Grapheme_Extend},
+ {0x1d185, 0x1d18b, HB_Grapheme_Extend},
+ {0x1d1aa, 0x1d1ad, HB_Grapheme_Extend},
+ {0x1d242, 0x1d244, HB_Grapheme_Extend},
+ {0xe0001, 0xe0001, HB_Grapheme_Control},
+ {0xe0020, 0xe007f, HB_Grapheme_Control},
+ {0xe0100, 0xe01ef, HB_Grapheme_Extend},
+};
+
+static const unsigned grapheme_break_properties_count = 1093;
+
+#endif // GRAPHEME_BREAK_PROPERTY_H_
diff --git a/third_party/harfbuzz/contrib/tables/script-properties.h b/third_party/harfbuzz/contrib/tables/script-properties.h
new file mode 100644
index 0000000..a6ff50b
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/script-properties.h
@@ -0,0 +1,297 @@
+// Generated from Unicode script tables
+
+#ifndef SCRIPT_PROPERTIES_H_
+#define SCRIPT_PROPERTIES_H_
+
+#include <stdint.h>
+#include "harfbuzz-shaper.h"
+
+struct script_property {
+ uint32_t range_start;
+ uint32_t range_end;
+ HB_Script script;
+};
+
+static const struct script_property script_properties[] = {
+ {0x300, 0x36f, HB_Script_Inherited},
+ {0x370, 0x373, HB_Script_Greek},
+ {0x375, 0x377, HB_Script_Greek},
+ {0x37a, 0x37d, HB_Script_Greek},
+ {0x384, 0x384, HB_Script_Greek},
+ {0x386, 0x386, HB_Script_Greek},
+ {0x388, 0x38a, HB_Script_Greek},
+ {0x38c, 0x38c, HB_Script_Greek},
+ {0x38e, 0x3a1, HB_Script_Greek},
+ {0x3a3, 0x3e1, HB_Script_Greek},
+ {0x3f0, 0x3ff, HB_Script_Greek},
+ {0x400, 0x523, HB_Script_Cyrillic},
+ {0x531, 0x556, HB_Script_Armenian},
+ {0x559, 0x55f, HB_Script_Armenian},
+ {0x561, 0x587, HB_Script_Armenian},
+ {0x58a, 0x58a, HB_Script_Armenian},
+ {0x591, 0x5c7, HB_Script_Hebrew},
+ {0x5d0, 0x5ea, HB_Script_Hebrew},
+ {0x5f0, 0x5f4, HB_Script_Hebrew},
+ {0x606, 0x60b, HB_Script_Arabic},
+ {0x60d, 0x61a, HB_Script_Arabic},
+ {0x61e, 0x61e, HB_Script_Arabic},
+ {0x621, 0x63f, HB_Script_Arabic},
+ {0x641, 0x64a, HB_Script_Arabic},
+ {0x64b, 0x655, HB_Script_Inherited},
+ {0x656, 0x65e, HB_Script_Arabic},
+ {0x66a, 0x66f, HB_Script_Arabic},
+ {0x670, 0x670, HB_Script_Inherited},
+ {0x671, 0x6dc, HB_Script_Arabic},
+ {0x6de, 0x6ff, HB_Script_Arabic},
+ {0x700, 0x70d, HB_Script_Syriac},
+ {0x70f, 0x74a, HB_Script_Syriac},
+ {0x74d, 0x74f, HB_Script_Syriac},
+ {0x750, 0x77f, HB_Script_Arabic},
+ {0x780, 0x7b1, HB_Script_Thaana},
+ {0x901, 0x939, HB_Script_Devanagari},
+ {0x93c, 0x94d, HB_Script_Devanagari},
+ {0x950, 0x950, HB_Script_Devanagari},
+ {0x951, 0x952, HB_Script_Inherited},
+ {0x953, 0x954, HB_Script_Devanagari},
+ {0x958, 0x963, HB_Script_Devanagari},
+ {0x966, 0x96f, HB_Script_Devanagari},
+ {0x971, 0x972, HB_Script_Devanagari},
+ {0x97b, 0x97f, HB_Script_Devanagari},
+ {0x981, 0x983, HB_Script_Bengali},
+ {0x985, 0x98c, HB_Script_Bengali},
+ {0x98f, 0x990, HB_Script_Bengali},
+ {0x993, 0x9a8, HB_Script_Bengali},
+ {0x9aa, 0x9b0, HB_Script_Bengali},
+ {0x9b2, 0x9b2, HB_Script_Bengali},
+ {0x9b6, 0x9b9, HB_Script_Bengali},
+ {0x9bc, 0x9c4, HB_Script_Bengali},
+ {0x9c7, 0x9c8, HB_Script_Bengali},
+ {0x9cb, 0x9ce, HB_Script_Bengali},
+ {0x9d7, 0x9d7, HB_Script_Bengali},
+ {0x9dc, 0x9dd, HB_Script_Bengali},
+ {0x9df, 0x9e3, HB_Script_Bengali},
+ {0x9e6, 0x9fa, HB_Script_Bengali},
+ {0xa01, 0xa03, HB_Script_Gurmukhi},
+ {0xa05, 0xa0a, HB_Script_Gurmukhi},
+ {0xa0f, 0xa10, HB_Script_Gurmukhi},
+ {0xa13, 0xa28, HB_Script_Gurmukhi},
+ {0xa2a, 0xa30, HB_Script_Gurmukhi},
+ {0xa32, 0xa33, HB_Script_Gurmukhi},
+ {0xa35, 0xa36, HB_Script_Gurmukhi},
+ {0xa38, 0xa39, HB_Script_Gurmukhi},
+ {0xa3c, 0xa3c, HB_Script_Gurmukhi},
+ {0xa3e, 0xa42, HB_Script_Gurmukhi},
+ {0xa47, 0xa48, HB_Script_Gurmukhi},
+ {0xa4b, 0xa4d, HB_Script_Gurmukhi},
+ {0xa51, 0xa51, HB_Script_Gurmukhi},
+ {0xa59, 0xa5c, HB_Script_Gurmukhi},
+ {0xa5e, 0xa5e, HB_Script_Gurmukhi},
+ {0xa66, 0xa75, HB_Script_Gurmukhi},
+ {0xa81, 0xa83, HB_Script_Gujarati},
+ {0xa85, 0xa8d, HB_Script_Gujarati},
+ {0xa8f, 0xa91, HB_Script_Gujarati},
+ {0xa93, 0xaa8, HB_Script_Gujarati},
+ {0xaaa, 0xab0, HB_Script_Gujarati},
+ {0xab2, 0xab3, HB_Script_Gujarati},
+ {0xab5, 0xab9, HB_Script_Gujarati},
+ {0xabc, 0xac5, HB_Script_Gujarati},
+ {0xac7, 0xac9, HB_Script_Gujarati},
+ {0xacb, 0xacd, HB_Script_Gujarati},
+ {0xad0, 0xad0, HB_Script_Gujarati},
+ {0xae0, 0xae3, HB_Script_Gujarati},
+ {0xae6, 0xaef, HB_Script_Gujarati},
+ {0xaf1, 0xaf1, HB_Script_Gujarati},
+ {0xb01, 0xb03, HB_Script_Oriya},
+ {0xb05, 0xb0c, HB_Script_Oriya},
+ {0xb0f, 0xb10, HB_Script_Oriya},
+ {0xb13, 0xb28, HB_Script_Oriya},
+ {0xb2a, 0xb30, HB_Script_Oriya},
+ {0xb32, 0xb33, HB_Script_Oriya},
+ {0xb35, 0xb39, HB_Script_Oriya},
+ {0xb3c, 0xb44, HB_Script_Oriya},
+ {0xb47, 0xb48, HB_Script_Oriya},
+ {0xb4b, 0xb4d, HB_Script_Oriya},
+ {0xb56, 0xb57, HB_Script_Oriya},
+ {0xb5c, 0xb5d, HB_Script_Oriya},
+ {0xb5f, 0xb63, HB_Script_Oriya},
+ {0xb66, 0xb71, HB_Script_Oriya},
+ {0xb82, 0xb83, HB_Script_Tamil},
+ {0xb85, 0xb8a, HB_Script_Tamil},
+ {0xb8e, 0xb90, HB_Script_Tamil},
+ {0xb92, 0xb95, HB_Script_Tamil},
+ {0xb99, 0xb9a, HB_Script_Tamil},
+ {0xb9c, 0xb9c, HB_Script_Tamil},
+ {0xb9e, 0xb9f, HB_Script_Tamil},
+ {0xba3, 0xba4, HB_Script_Tamil},
+ {0xba8, 0xbaa, HB_Script_Tamil},
+ {0xbae, 0xbb9, HB_Script_Tamil},
+ {0xbbe, 0xbc2, HB_Script_Tamil},
+ {0xbc6, 0xbc8, HB_Script_Tamil},
+ {0xbca, 0xbcd, HB_Script_Tamil},
+ {0xbd0, 0xbd0, HB_Script_Tamil},
+ {0xbd7, 0xbd7, HB_Script_Tamil},
+ {0xbe6, 0xbfa, HB_Script_Tamil},
+ {0xc01, 0xc03, HB_Script_Telugu},
+ {0xc05, 0xc0c, HB_Script_Telugu},
+ {0xc0e, 0xc10, HB_Script_Telugu},
+ {0xc12, 0xc28, HB_Script_Telugu},
+ {0xc2a, 0xc33, HB_Script_Telugu},
+ {0xc35, 0xc39, HB_Script_Telugu},
+ {0xc3d, 0xc44, HB_Script_Telugu},
+ {0xc46, 0xc48, HB_Script_Telugu},
+ {0xc4a, 0xc4d, HB_Script_Telugu},
+ {0xc55, 0xc56, HB_Script_Telugu},
+ {0xc58, 0xc59, HB_Script_Telugu},
+ {0xc60, 0xc63, HB_Script_Telugu},
+ {0xc66, 0xc6f, HB_Script_Telugu},
+ {0xc78, 0xc7f, HB_Script_Telugu},
+ {0xc82, 0xc83, HB_Script_Kannada},
+ {0xc85, 0xc8c, HB_Script_Kannada},
+ {0xc8e, 0xc90, HB_Script_Kannada},
+ {0xc92, 0xca8, HB_Script_Kannada},
+ {0xcaa, 0xcb3, HB_Script_Kannada},
+ {0xcb5, 0xcb9, HB_Script_Kannada},
+ {0xcbc, 0xcc4, HB_Script_Kannada},
+ {0xcc6, 0xcc8, HB_Script_Kannada},
+ {0xcca, 0xccd, HB_Script_Kannada},
+ {0xcd5, 0xcd6, HB_Script_Kannada},
+ {0xcde, 0xcde, HB_Script_Kannada},
+ {0xce0, 0xce3, HB_Script_Kannada},
+ {0xce6, 0xcef, HB_Script_Kannada},
+ {0xd02, 0xd03, HB_Script_Malayalam},
+ {0xd05, 0xd0c, HB_Script_Malayalam},
+ {0xd0e, 0xd10, HB_Script_Malayalam},
+ {0xd12, 0xd28, HB_Script_Malayalam},
+ {0xd2a, 0xd39, HB_Script_Malayalam},
+ {0xd3d, 0xd44, HB_Script_Malayalam},
+ {0xd46, 0xd48, HB_Script_Malayalam},
+ {0xd4a, 0xd4d, HB_Script_Malayalam},
+ {0xd57, 0xd57, HB_Script_Malayalam},
+ {0xd60, 0xd63, HB_Script_Malayalam},
+ {0xd66, 0xd75, HB_Script_Malayalam},
+ {0xd79, 0xd7f, HB_Script_Malayalam},
+ {0xd82, 0xd83, HB_Script_Sinhala},
+ {0xd85, 0xd96, HB_Script_Sinhala},
+ {0xd9a, 0xdb1, HB_Script_Sinhala},
+ {0xdb3, 0xdbb, HB_Script_Sinhala},
+ {0xdbd, 0xdbd, HB_Script_Sinhala},
+ {0xdc0, 0xdc6, HB_Script_Sinhala},
+ {0xdca, 0xdca, HB_Script_Sinhala},
+ {0xdcf, 0xdd4, HB_Script_Sinhala},
+ {0xdd6, 0xdd6, HB_Script_Sinhala},
+ {0xdd8, 0xddf, HB_Script_Sinhala},
+ {0xdf2, 0xdf4, HB_Script_Sinhala},
+ {0xe01, 0xe3a, HB_Script_Thai},
+ {0xe40, 0xe5b, HB_Script_Thai},
+ {0xe81, 0xe82, HB_Script_Lao},
+ {0xe84, 0xe84, HB_Script_Lao},
+ {0xe87, 0xe88, HB_Script_Lao},
+ {0xe8a, 0xe8a, HB_Script_Lao},
+ {0xe8d, 0xe8d, HB_Script_Lao},
+ {0xe94, 0xe97, HB_Script_Lao},
+ {0xe99, 0xe9f, HB_Script_Lao},
+ {0xea1, 0xea3, HB_Script_Lao},
+ {0xea5, 0xea5, HB_Script_Lao},
+ {0xea7, 0xea7, HB_Script_Lao},
+ {0xeaa, 0xeab, HB_Script_Lao},
+ {0xead, 0xeb9, HB_Script_Lao},
+ {0xebb, 0xebd, HB_Script_Lao},
+ {0xec0, 0xec4, HB_Script_Lao},
+ {0xec6, 0xec6, HB_Script_Lao},
+ {0xec8, 0xecd, HB_Script_Lao},
+ {0xed0, 0xed9, HB_Script_Lao},
+ {0xedc, 0xedd, HB_Script_Lao},
+ {0xf00, 0xf47, HB_Script_Tibetan},
+ {0xf49, 0xf6c, HB_Script_Tibetan},
+ {0xf71, 0xf8b, HB_Script_Tibetan},
+ {0xf90, 0xf97, HB_Script_Tibetan},
+ {0xf99, 0xfbc, HB_Script_Tibetan},
+ {0xfbe, 0xfcc, HB_Script_Tibetan},
+ {0xfce, 0xfd4, HB_Script_Tibetan},
+ {0x1000, 0x1099, HB_Script_Myanmar},
+ {0x109e, 0x109f, HB_Script_Myanmar},
+ {0x10a0, 0x10c5, HB_Script_Georgian},
+ {0x10d0, 0x10fa, HB_Script_Georgian},
+ {0x10fc, 0x10fc, HB_Script_Georgian},
+ {0x1100, 0x1159, HB_Script_Hangul},
+ {0x115f, 0x11a2, HB_Script_Hangul},
+ {0x11a8, 0x11f9, HB_Script_Hangul},
+ {0x1680, 0x169c, HB_Script_Ogham},
+ {0x16a0, 0x16ea, HB_Script_Runic},
+ {0x16ee, 0x16f0, HB_Script_Runic},
+ {0x1780, 0x17dd, HB_Script_Khmer},
+ {0x17e0, 0x17e9, HB_Script_Khmer},
+ {0x17f0, 0x17f9, HB_Script_Khmer},
+ {0x19e0, 0x19ff, HB_Script_Khmer},
+ {0x1d26, 0x1d2a, HB_Script_Greek},
+ {0x1d2b, 0x1d2b, HB_Script_Cyrillic},
+ {0x1d5d, 0x1d61, HB_Script_Greek},
+ {0x1d66, 0x1d6a, HB_Script_Greek},
+ {0x1d78, 0x1d78, HB_Script_Cyrillic},
+ {0x1dbf, 0x1dbf, HB_Script_Greek},
+ {0x1dc0, 0x1de6, HB_Script_Inherited},
+ {0x1dfe, 0x1dff, HB_Script_Inherited},
+ {0x1f00, 0x1f15, HB_Script_Greek},
+ {0x1f18, 0x1f1d, HB_Script_Greek},
+ {0x1f20, 0x1f45, HB_Script_Greek},
+ {0x1f48, 0x1f4d, HB_Script_Greek},
+ {0x1f50, 0x1f57, HB_Script_Greek},
+ {0x1f59, 0x1f59, HB_Script_Greek},
+ {0x1f5b, 0x1f5b, HB_Script_Greek},
+ {0x1f5d, 0x1f5d, HB_Script_Greek},
+ {0x1f5f, 0x1f7d, HB_Script_Greek},
+ {0x1f80, 0x1fb4, HB_Script_Greek},
+ {0x1fb6, 0x1fc4, HB_Script_Greek},
+ {0x1fc6, 0x1fd3, HB_Script_Greek},
+ {0x1fd6, 0x1fdb, HB_Script_Greek},
+ {0x1fdd, 0x1fef, HB_Script_Greek},
+ {0x1ff2, 0x1ff4, HB_Script_Greek},
+ {0x1ff6, 0x1ffe, HB_Script_Greek},
+ {0x200c, 0x200d, HB_Script_Inherited},
+ {0x20d0, 0x20f0, HB_Script_Inherited},
+ {0x2126, 0x2126, HB_Script_Greek},
+ {0x2d00, 0x2d25, HB_Script_Georgian},
+ {0x2de0, 0x2dff, HB_Script_Cyrillic},
+ {0x302a, 0x302f, HB_Script_Inherited},
+ {0x3099, 0x309a, HB_Script_Inherited},
+ {0x3131, 0x318e, HB_Script_Hangul},
+ {0x3200, 0x321e, HB_Script_Hangul},
+ {0x3260, 0x327e, HB_Script_Hangul},
+ {0xa640, 0xa65f, HB_Script_Cyrillic},
+ {0xa662, 0xa673, HB_Script_Cyrillic},
+ {0xa67c, 0xa697, HB_Script_Cyrillic},
+ {0xac00, 0xd7a3, HB_Script_Hangul},
+ {0xfb13, 0xfb17, HB_Script_Armenian},
+ {0xfb1d, 0xfb36, HB_Script_Hebrew},
+ {0xfb38, 0xfb3c, HB_Script_Hebrew},
+ {0xfb3e, 0xfb3e, HB_Script_Hebrew},
+ {0xfb40, 0xfb41, HB_Script_Hebrew},
+ {0xfb43, 0xfb44, HB_Script_Hebrew},
+ {0xfb46, 0xfb4f, HB_Script_Hebrew},
+ {0xfb50, 0xfbb1, HB_Script_Arabic},
+ {0xfbd3, 0xfd3d, HB_Script_Arabic},
+ {0xfd50, 0xfd8f, HB_Script_Arabic},
+ {0xfd92, 0xfdc7, HB_Script_Arabic},
+ {0xfdf0, 0xfdfc, HB_Script_Arabic},
+ {0xfe00, 0xfe0f, HB_Script_Inherited},
+ {0xfe20, 0xfe26, HB_Script_Inherited},
+ {0xfe70, 0xfe74, HB_Script_Arabic},
+ {0xfe76, 0xfefc, HB_Script_Arabic},
+ {0xffa0, 0xffbe, HB_Script_Hangul},
+ {0xffc2, 0xffc7, HB_Script_Hangul},
+ {0xffca, 0xffcf, HB_Script_Hangul},
+ {0xffd2, 0xffd7, HB_Script_Hangul},
+ {0xffda, 0xffdc, HB_Script_Hangul},
+ {0x10140, 0x1018a, HB_Script_Greek},
+ {0x101fd, 0x101fd, HB_Script_Inherited},
+ {0x1d167, 0x1d169, HB_Script_Inherited},
+ {0x1d17b, 0x1d182, HB_Script_Inherited},
+ {0x1d185, 0x1d18b, HB_Script_Inherited},
+ {0x1d1aa, 0x1d1ad, HB_Script_Inherited},
+ {0x1d200, 0x1d245, HB_Script_Greek},
+ {0xe0100, 0xe01ef, HB_Script_Inherited},
+};
+
+static const unsigned script_properties_count = 277;
+
+#endif // SCRIPT_PROPERTIES_H_
diff --git a/third_party/harfbuzz/contrib/tables/scripts-parse.py b/third_party/harfbuzz/contrib/tables/scripts-parse.py
new file mode 100644
index 0000000..23bac10
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/scripts-parse.py
@@ -0,0 +1,75 @@
+import sys
+from unicode_parse_common import *
+
+# http://www.unicode.org/Public/5.1.0/ucd/Scripts.txt
+
+script_to_harfbuzz = {
+ # This is the list of HB_Script_* at the time of writing
+ 'Common': 'HB_Script_Common',
+ 'Greek': 'HB_Script_Greek',
+ 'Cyrillic': 'HB_Script_Cyrillic',
+ 'Armenian': 'HB_Script_Armenian',
+ 'Hebrew': 'HB_Script_Hebrew',
+ 'Arabic': 'HB_Script_Arabic',
+ 'Syriac': 'HB_Script_Syriac',
+ 'Thaana': 'HB_Script_Thaana',
+ 'Devanagari': 'HB_Script_Devanagari',
+ 'Bengali': 'HB_Script_Bengali',
+ 'Gurmukhi': 'HB_Script_Gurmukhi',
+ 'Gujarati': 'HB_Script_Gujarati',
+ 'Oriya': 'HB_Script_Oriya',
+ 'Tamil': 'HB_Script_Tamil',
+ 'Telugu': 'HB_Script_Telugu',
+ 'Kannada': 'HB_Script_Kannada',
+ 'Malayalam': 'HB_Script_Malayalam',
+ 'Sinhala': 'HB_Script_Sinhala',
+ 'Thai': 'HB_Script_Thai',
+ 'Lao': 'HB_Script_Lao',
+ 'Tibetan': 'HB_Script_Tibetan',
+ 'Myanmar': 'HB_Script_Myanmar',
+ 'Georgian': 'HB_Script_Georgian',
+ 'Hangul': 'HB_Script_Hangul',
+ 'Ogham': 'HB_Script_Ogham',
+ 'Runic': 'HB_Script_Runic',
+ 'Khmer': 'HB_Script_Khmer',
+ 'Inherited': 'HB_Script_Inherited',
+}
+
+class ScriptDict(object):
+ def __init__(self, base):
+ self.base = base
+
+ def __getitem__(self, key):
+ r = self.base.get(key, None)
+ if r is None:
+ return 'HB_Script_Common'
+ return r
+
+def main(infile, outfile):
+ ranges = unicode_file_parse(infile,
+ ScriptDict(script_to_harfbuzz),
+ 'HB_Script_Common')
+ ranges = sort_and_merge(ranges)
+
+ print >>outfile, '// Generated from Unicode script tables\n'
+ print >>outfile, '#ifndef SCRIPT_PROPERTIES_H_'
+ print >>outfile, '#define SCRIPT_PROPERTIES_H_\n'
+ print >>outfile, '#include <stdint.h>'
+ print >>outfile, '#include "harfbuzz-shaper.h"\n'
+ print >>outfile, 'struct script_property {'
+ print >>outfile, ' uint32_t range_start;'
+ print >>outfile, ' uint32_t range_end;'
+ print >>outfile, ' HB_Script script;'
+ print >>outfile, '};\n'
+ print >>outfile, 'static const struct script_property script_properties[] = {'
+ for (start, end, value) in ranges:
+ print >>outfile, ' {0x%x, 0x%x, %s},' % (start, end, value)
+ print >>outfile, '};\n'
+ print >>outfile, 'static const unsigned script_properties_count = %d;\n' % len(ranges)
+ print >>outfile, '#endif // SCRIPT_PROPERTIES_H_'
+
+if __name__ == '__main__':
+ if len(sys.argv) != 3:
+ print 'Usage: %s <input .txt> <output .h>' % sys.argv[0]
+ else:
+ main(file(sys.argv[1], 'r'), file(sys.argv[2], 'w+'))
diff --git a/third_party/harfbuzz/contrib/tables/unicode_parse_common.py b/third_party/harfbuzz/contrib/tables/unicode_parse_common.py
new file mode 100644
index 0000000..ac26eca
--- /dev/null
+++ b/third_party/harfbuzz/contrib/tables/unicode_parse_common.py
@@ -0,0 +1,70 @@
+def lines_get(f):
+ '''Parse a file like object, removing comments and returning a list of
+ lines.'''
+ def cut_comment(line):
+ first_hash = line.find('#')
+ if first_hash == -1:
+ return line
+ return line[:first_hash]
+
+ return [x for x in [cut_comment(x[:-1]) for x in f.readlines()] if len(x)]
+
+def line_split(line):
+ '''Split a line based on a semicolon separator.'''
+ def normalise(word):
+ return word.lstrip().rstrip()
+ return [normalise(x) for x in line.split(';')]
+
+def codepoints_parse(token):
+ '''Parse a Unicode style code-point range. Return either a single value or a
+ tuple of (start, end) for a range of code-points.'''
+ def fromHex(token):
+ return int(token, 16)
+ parts = token.split('..')
+ if len(parts) == 2:
+ return (fromHex(parts[0]), fromHex(parts[1]))
+ elif len(parts) == 1:
+ return fromHex(parts[0])
+ else:
+ raise ValueError(token)
+
+def unicode_file_parse(input, map, default_value = None):
+ '''Parse a file like object, @input where the first column is a code-point
+ range and the second column is mapped via the given dict, @map.'''
+ ranges = []
+ tokens = [line_split(x) for x in lines_get(input)]
+ for line in tokens:
+ if len(line) == 2:
+ codepoints = codepoints_parse(line[0])
+ value = map[line[1]]
+ if value == default_value:
+ continue
+
+ if type(codepoints) == int:
+ codepoints = (codepoints, codepoints)
+
+ ranges.append((codepoints[0], codepoints[1], value))
+ else:
+ raise ValueError(line)
+
+ return ranges
+
+def sort_and_merge(ranges):
+ '''Given a list of (start, end, value), merge elements where the ranges are
+ continuous and the values are the same.'''
+ output = []
+ ranges.sort()
+ current = None
+ for v in ranges:
+ if current is None:
+ current = v
+ continue
+ if current[1] + 1 == v[0] and current[2] == v[2]:
+ current = (current[0], v[1], v[2])
+ else:
+ output.append(current)
+ current = v
+ if current is not None:
+ output.append(current)
+
+ return output
diff --git a/third_party/harfbuzz/harfbuzz.gyp b/third_party/harfbuzz/harfbuzz.gyp
new file mode 100644
index 0000000..5e98ddb
--- /dev/null
+++ b/third_party/harfbuzz/harfbuzz.gyp
@@ -0,0 +1,69 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../../build/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'harfbuzz',
+ 'type': 'static_library',
+ 'sources': [
+ 'src/harfbuzz-buffer.c',
+ 'src/harfbuzz-stream.c',
+ 'src/harfbuzz-dump.c',
+ 'src/harfbuzz-gdef.c',
+ 'src/harfbuzz-gpos.c',
+ 'src/harfbuzz-gsub.c',
+ 'src/harfbuzz-impl.c',
+ 'src/harfbuzz-open.c',
+ 'src/harfbuzz-shaper.cpp',
+ 'src/harfbuzz-tibetan.c',
+ 'src/harfbuzz-khmer.c',
+ 'src/harfbuzz-indic.cpp',
+ 'src/harfbuzz-hebrew.c',
+ 'src/harfbuzz-arabic.c',
+ 'src/harfbuzz-hangul.c',
+ 'src/harfbuzz-myanmar.c',
+ 'src/harfbuzz-thai.c',
+ ],
+ 'include_dirs': [
+ 'src',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'src',
+ ],
+ },
+ 'dependencies': [
+ '../../build/linux/system.gyp:freetype2',
+ ],
+ },
+ {
+ 'target_name': 'harfbuzz_interface',
+ 'type': 'static_library',
+ 'sources': [
+ 'contrib/harfbuzz-freetype.c',
+ 'contrib/harfbuzz-unicode.c',
+ 'contrib/harfbuzz-unicode-tables.c',
+ ],
+ 'include_dirs': [
+ 'src',
+ 'contrib',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'contrib',
+ ],
+ },
+ 'dependencies': [
+ '../../build/linux/system.gyp:freetype2',
+ ],
+ },
+ ],
+}
diff --git a/third_party/harfbuzz/src/.gitignore b/third_party/harfbuzz/src/.gitignore
new file mode 100644
index 0000000..74de98b
--- /dev/null
+++ b/third_party/harfbuzz/src/.gitignore
@@ -0,0 +1,7 @@
+*.o
+*.lo
+Makefile
+*.la
+.deps
+.libs
+*~
diff --git a/third_party/harfbuzz/src/Makefile.am b/third_party/harfbuzz/src/Makefile.am
new file mode 100644
index 0000000..2b0fb1d
--- /dev/null
+++ b/third_party/harfbuzz/src/Makefile.am
@@ -0,0 +1,68 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LTLIBRARIES = libharfbuzz-1.la
+
+MAINSOURCES = \
+ harfbuzz-buffer.c \
+ harfbuzz-stream.c \
+ harfbuzz-dump.c \
+ harfbuzz-gdef.c \
+ harfbuzz-gpos.c \
+ harfbuzz-gsub.c \
+ harfbuzz-impl.c \
+ harfbuzz-open.c \
+ harfbuzz-shaper.cpp \
+ harfbuzz-tibetan.c \
+ harfbuzz-khmer.c \
+ harfbuzz-indic.cpp \
+ harfbuzz-hebrew.c \
+ harfbuzz-arabic.c \
+ harfbuzz-hangul.c \
+ harfbuzz-myanmar.c \
+ harfbuzz-thai.c
+
+EXTRA_SOURCES = harfbuzz.c
+
+PUBLICHEADERS = \
+ harfbuzz.h \
+ harfbuzz-buffer.h \
+ harfbuzz-dump.h \
+ harfbuzz-gdef.h \
+ harfbuzz-gpos.h \
+ harfbuzz-gsub.h \
+ harfbuzz-open.h \
+ harfbuzz-global.h \
+ harfbuzz-external.h \
+ harfbuzz-shaper.h \
+ harfbuzz-stream.h
+
+PRIVATEHEADERS = \
+ harfbuzz-impl.h \
+ harfbuzz-buffer-private.h \
+ harfbuzz-stream-private.h \
+ harfbuzz-gdef-private.h \
+ harfbuzz-gpos-private.h \
+ harfbuzz-gsub-private.h \
+ harfbuzz-open-private.h \
+ harfbuzz-shaper-private.h
+
+libharfbuzz_1_la_SOURCES = \
+ $(MAINSOURCES) \
+ $(PUBLICHEADERS) \
+ $(PRIVATEHEADERS)
+
+#noinst_PROGRAMS = harfbuzz-dump
+#
+#harfbuzz_dump_SOURCES = \
+# harfbuzz-dump-main.c
+#
+#harfbuzz_dump_LDADD = \
+# libharfbuzz-1.la
+
+EXTRA_DIST = \
+ README \
+ COPYING.FTL \
+ COPYING.GPL \
+ COPYING \
+ $(EXTRA_SOURCES)
+
diff --git a/third_party/harfbuzz/src/harfbuzz-arabic.c b/third_party/harfbuzz/src/harfbuzz-arabic.c
new file mode 100644
index 0000000..0609232
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-arabic.c
@@ -0,0 +1,1090 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+
+static const HB_UChar16 ReplacementCharacter = 0xfffd;
+
+typedef struct {
+ unsigned char shape;
+ unsigned char justification;
+} HB_ArabicProperties;
+
+typedef enum {
+ XIsolated,
+ XFinal,
+ XInitial,
+ XMedial,
+ /* intermediate state */
+ XCausing
+} ArabicShape;
+
+/*
+// these groups correspond to the groups defined in the Unicode standard.
+// Some of these groups are equal with regards to both joining and line breaking behaviour,
+// and thus have the same enum value
+//
+// I'm not sure the mapping of syriac to arabic enums is correct with regards to justification, but as
+// I couldn't find any better document I'll hope for the best.
+*/
+typedef enum {
+ /* NonJoining */
+ ArabicNone,
+ ArabicSpace,
+ /* Transparent */
+ Transparent,
+ /* Causing */
+ Center,
+ Kashida,
+
+ /* Arabic */
+ /* Dual */
+ Beh,
+ Noon,
+ Meem = Noon,
+ Heh = Noon,
+ KnottedHeh = Noon,
+ HehGoal = Noon,
+ SwashKaf = Noon,
+ Yeh,
+ Hah,
+ Seen,
+ Sad = Seen,
+ Tah,
+ Kaf = Tah,
+ Gaf = Tah,
+ Lam = Tah,
+ Ain,
+ Feh = Ain,
+ Qaf = Ain,
+ /* Right */
+ Alef,
+ Waw,
+ Dal,
+ TehMarbuta = Dal,
+ Reh,
+ HamzaOnHehGoal,
+ YehWithTail = HamzaOnHehGoal,
+ YehBarre = HamzaOnHehGoal,
+
+ /* Syriac */
+ /* Dual */
+ Beth = Beh,
+ Gamal = Ain,
+ Heth = Noon,
+ Teth = Hah,
+ Yudh = Noon,
+ Kaph = Noon,
+ Lamadh = Lam,
+ Mim = Noon,
+ Nun = Noon,
+ Semakh = Noon,
+ FinalSemakh = Noon,
+ SyriacE = Ain,
+ Pe = Ain,
+ ReversedPe = Hah,
+ Qaph = Noon,
+ Shin = Noon,
+ Fe = Ain,
+
+ /* Right */
+ Alaph = Alef,
+ Dalath = Dal,
+ He = Dal,
+ SyriacWaw = Waw,
+ Zain = Alef,
+ YudhHe = Waw,
+ Sadhe = HamzaOnHehGoal,
+ Taw = Dal,
+
+ /* Compiler bug? Otherwise ArabicGroupsEnd would be equal to Dal + 1. */
+ Dummy = HamzaOnHehGoal,
+ ArabicGroupsEnd
+} ArabicGroup;
+
+static const unsigned char arabic_group[0x150] = {
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+
+ ArabicNone, ArabicNone, Alef, Alef,
+ Waw, Alef, Yeh, Alef,
+ Beh, TehMarbuta, Beh, Beh,
+ Hah, Hah, Hah, Dal,
+
+ Dal, Reh, Reh, Seen,
+ Seen, Sad, Sad, Tah,
+ Tah, Ain, Ain, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+
+ /* 0x640 */
+ Kashida, Feh, Qaf, Kaf,
+ Lam, Meem, Noon, Heh,
+ Waw, Yeh, Yeh, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, Beh, Qaf,
+
+ Transparent, Alef, Alef, Alef,
+ ArabicNone, Alef, Waw, Waw,
+ Yeh, Beh, Beh, Beh,
+ Beh, Beh, Beh, Beh,
+
+ /* 0x680 */
+ Beh, Hah, Hah, Hah,
+ Hah, Hah, Hah, Hah,
+ Dal, Dal, Dal, Dal,
+ Dal, Dal, Dal, Dal,
+
+ Dal, Reh, Reh, Reh,
+ Reh, Reh, Reh, Reh,
+ Reh, Reh, Seen, Seen,
+ Seen, Sad, Sad, Tah,
+
+ Ain, Feh, Feh, Feh,
+ Feh, Feh, Feh, Qaf,
+ Qaf, Gaf, SwashKaf, Gaf,
+ Kaf, Kaf, Kaf, Gaf,
+
+ Gaf, Gaf, Gaf, Gaf,
+ Gaf, Lam, Lam, Lam,
+ Lam, Noon, Noon, Noon,
+ Noon, Noon, KnottedHeh, Hah,
+
+ /* 0x6c0 */
+ TehMarbuta, HehGoal, HamzaOnHehGoal, HamzaOnHehGoal,
+ Waw, Waw, Waw, Waw,
+ Waw, Waw, Waw, Waw,
+ Yeh, YehWithTail, Yeh, Waw,
+
+ Yeh, Yeh, YehBarre, YehBarre,
+ ArabicNone, TehMarbuta, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, ArabicNone, ArabicNone, Transparent,
+
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, ArabicNone, ArabicNone, Transparent,
+ Transparent, ArabicNone, Transparent, Transparent,
+ Transparent, Transparent, Dal, Reh,
+
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, Seen, Sad,
+ Ain, ArabicNone, ArabicNone, KnottedHeh,
+
+ /* 0x700 */
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+ ArabicNone, ArabicNone, ArabicNone, ArabicNone,
+
+ Alaph, Transparent, Beth, Gamal,
+ Gamal, Dalath, Dalath, He,
+ SyriacWaw, Zain, Heth, Teth,
+ Teth, Yudh, YudhHe, Kaph,
+
+ Lamadh, Mim, Nun, Semakh,
+ FinalSemakh, SyriacE, Pe, ReversedPe,
+ Sadhe, Qaph, Dalath, Shin,
+ Taw, Beth, Gamal, Dalath,
+
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, Transparent,
+ Transparent, Transparent, Transparent, ArabicNone,
+ ArabicNone, Zain, Kaph, Fe,
+};
+
+static ArabicGroup arabicGroup(unsigned short uc)
+{
+ if (uc >= 0x0600 && uc < 0x750)
+ return (ArabicGroup) arabic_group[uc-0x600];
+ else if (uc == 0x200d)
+ return Center;
+ else if (HB_GetUnicodeCharCategory(uc) == HB_Separator_Space)
+ return ArabicSpace;
+ else
+ return ArabicNone;
+}
+
+
+/*
+ Arabic shaping obeys a number of rules according to the joining classes (see Unicode book, section on
+ arabic).
+
+ Each unicode char has a joining class (right, dual (left&right), center (joincausing) or transparent).
+ transparent joining is not encoded in HB_UChar16::joining(), but applies to all combining marks and format marks.
+
+ Right join-causing: dual + center
+ Left join-causing: dual + right + center
+
+ Rules are as follows (for a string already in visual order, as we have it here):
+
+ R1 Transparent characters do not affect joining behaviour.
+ R2 A right joining character, that has a right join-causing char on the right will get form XRight
+ (R3 A left joining character, that has a left join-causing char on the left will get form XLeft)
+ Note: the above rule is meaningless, as there are no pure left joining characters defined in Unicode
+ R4 A dual joining character, that has a left join-causing char on the left and a right join-causing char on
+ the right will get form XMedial
+ R5 A dual joining character, that has a right join causing char on the right, and no left join causing char on the left
+ will get form XRight
+ R6 A dual joining character, that has a left join causing char on the left, and no right join causing char on the right
+ will get form XLeft
+ R7 Otherwise the character will get form XIsolated
+
+ Additionally we have to do the minimal ligature support for lam-alef ligatures:
+
+ L1 Transparent characters do not affect ligature behaviour.
+ L2 Any sequence of Alef(XRight) + Lam(XMedial) will form the ligature Alef.Lam(XLeft)
+ L3 Any sequence of Alef(XRight) + Lam(XLeft) will form the ligature Alef.Lam(XIsolated)
+
+ The state table below handles rules R1-R7.
+*/
+
+typedef enum {
+ JNone,
+ JCausing,
+ JDual,
+ JRight,
+ JTransparent
+} Joining;
+
+static const Joining joining_for_group[ArabicGroupsEnd] = {
+ /* NonJoining */
+ JNone, /* ArabicNone */
+ JNone, /* ArabicSpace */
+ /* Transparent */
+ JTransparent, /* Transparent */
+ /* Causing */
+ JCausing, /* Center */
+ JCausing, /* Kashida */
+ /* Dual */
+ JDual, /* Beh */
+ JDual, /* Noon */
+ JDual, /* Yeh */
+ JDual, /* Hah */
+ JDual, /* Seen */
+ JDual, /* Tah */
+ JDual, /* Ain */
+ /* Right */
+ JRight, /* Alef */
+ JRight, /* Waw */
+ JRight, /* Dal */
+ JRight, /* Reh */
+ JRight /* HamzaOnHehGoal */
+};
+
+
+typedef struct {
+ ArabicShape form1;
+ ArabicShape form2;
+} JoiningPair;
+
+static const JoiningPair joining_table[5][4] =
+/* None, Causing, Dual, Right */
+{
+ { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XInitial }, { XIsolated, XIsolated } }, /* XIsolated */
+ { { XFinal, XIsolated }, { XFinal, XCausing }, { XFinal, XInitial }, { XFinal, XIsolated } }, /* XFinal */
+ { { XIsolated, XIsolated }, { XInitial, XCausing }, { XInitial, XMedial }, { XInitial, XFinal } }, /* XInitial */
+ { { XFinal, XIsolated }, { XMedial, XCausing }, { XMedial, XMedial }, { XMedial, XFinal } }, /* XMedial */
+ { { XIsolated, XIsolated }, { XIsolated, XCausing }, { XIsolated, XMedial }, { XIsolated, XFinal } }, /* XCausing */
+};
+
+
+/*
+According to http://www.microsoft.com/middleeast/Arabicdev/IE6/KBase.asp
+
+1. Find the priority of the connecting opportunities in each word
+2. Add expansion at the highest priority connection opportunity
+3. If more than one connection opportunity have the same highest value,
+ use the opportunity closest to the end of the word.
+
+Following is a chart that provides the priority for connection
+opportunities and where expansion occurs. The character group names
+are those in table 6.6 of the UNICODE 2.0 book.
+
+
+PrioritY Glyph Condition Kashida Location
+
+Arabic_Kashida User inserted Kashida The user entered a Kashida in a position. After the user
+ (Shift+j or Shift+[E with hat]) Thus, it is the highest priority to insert an inserted kashida
+ automatic kashida.
+
+Arabic_Seen Seen, Sad Connecting to the next character. After the character.
+ (Initial or medial form).
+
+Arabic_HaaDal Teh Marbutah, Haa, Dal Connecting to previous character. Before the final form
+ of these characters.
+
+Arabic_Alef Alef, Tah, Lam, Connecting to previous character. Before the final form
+ Kaf and Gaf of these characters.
+
+Arabic_BaRa Reh, Yeh Connected to medial Beh Before preceding medial Baa
+
+Arabic_Waw Waw, Ain, Qaf, Feh Connecting to previous character. Before the final form of
+ these characters.
+
+Arabic_Normal Other connecting Connecting to previous character. Before the final form
+ characters of these characters.
+
+
+
+This seems to imply that we have at most one kashida point per arabic word.
+
+*/
+
+static void getArabicProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties)
+{
+/* qDebug("arabicSyriacOpenTypeShape: properties:"); */
+ int lastPos = 0;
+ int lastGroup = ArabicNone;
+ int i = 0;
+
+ ArabicGroup group = arabicGroup(chars[0]);
+ Joining j = joining_for_group[group];
+ ArabicShape shape = joining_table[XIsolated][j].form2;
+ properties[0].justification = HB_NoJustification;
+
+ for (i = 1; i < len; ++i) {
+ /* #### fix handling for spaces and punktuation */
+ properties[i].justification = HB_NoJustification;
+
+ group = arabicGroup(chars[i]);
+ j = joining_for_group[group];
+
+ if (j == JTransparent) {
+ properties[i].shape = XIsolated;
+ continue;
+ }
+
+ properties[lastPos].shape = joining_table[shape][j].form1;
+ shape = joining_table[shape][j].form2;
+
+ switch(lastGroup) {
+ case Seen:
+ if (properties[lastPos].shape == XInitial || properties[lastPos].shape == XMedial)
+ properties[i-1].justification = HB_Arabic_Seen;
+ break;
+ case Hah:
+ if (properties[lastPos].shape == XFinal)
+ properties[lastPos-1].justification = HB_Arabic_HaaDal;
+ break;
+ case Alef:
+ if (properties[lastPos].shape == XFinal)
+ properties[lastPos-1].justification = HB_Arabic_Alef;
+ break;
+ case Ain:
+ if (properties[lastPos].shape == XFinal)
+ properties[lastPos-1].justification = HB_Arabic_Waw;
+ break;
+ case Noon:
+ if (properties[lastPos].shape == XFinal)
+ properties[lastPos-1].justification = HB_Arabic_Normal;
+ break;
+ case ArabicNone:
+ break;
+
+ default:
+ assert(FALSE);
+ }
+
+ lastGroup = ArabicNone;
+
+ switch(group) {
+ case ArabicNone:
+ case Transparent:
+ /* ### Center should probably be treated as transparent when it comes to justification. */
+ case Center:
+ break;
+ case ArabicSpace:
+ properties[i].justification = HB_Arabic_Space;
+ break;
+ case Kashida:
+ properties[i].justification = HB_Arabic_Kashida;
+ break;
+ case Seen:
+ lastGroup = Seen;
+ break;
+
+ case Hah:
+ case Dal:
+ lastGroup = Hah;
+ break;
+
+ case Alef:
+ case Tah:
+ lastGroup = Alef;
+ break;
+
+ case Yeh:
+ case Reh:
+ if (properties[lastPos].shape == XMedial && arabicGroup(chars[lastPos]) == Beh)
+ properties[lastPos-1].justification = HB_Arabic_BaRa;
+ break;
+
+ case Ain:
+ case Waw:
+ lastGroup = Ain;
+ break;
+
+ case Noon:
+ case Beh:
+ case HamzaOnHehGoal:
+ lastGroup = Noon;
+ break;
+ case ArabicGroupsEnd:
+ assert(FALSE);
+ }
+
+ lastPos = i;
+ }
+ properties[lastPos].shape = joining_table[shape][JNone].form1;
+
+
+ /*
+ for (int i = 0; i < len; ++i)
+ qDebug("arabic properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification);
+ */
+}
+
+/*
+// The unicode to unicode shaping codec.
+// does only presentation forms B at the moment, but that should be enough for
+// simple display
+*/
+static const hb_uint16 arabicUnicodeMapping[256][2] = {
+ /* base of shaped forms, and number-1 of them (0 for non shaping,
+ 1 for right binding and 3 for dual binding */
+
+ /* These are just the glyphs available in Unicode,
+ some characters are in R class, but have no glyphs in Unicode. */
+
+ { 0x0600, 0 }, /* 0x0600 */
+ { 0x0601, 0 }, /* 0x0601 */
+ { 0x0602, 0 }, /* 0x0602 */
+ { 0x0603, 0 }, /* 0x0603 */
+ { 0x0604, 0 }, /* 0x0604 */
+ { 0x0605, 0 }, /* 0x0605 */
+ { 0x0606, 0 }, /* 0x0606 */
+ { 0x0607, 0 }, /* 0x0607 */
+ { 0x0608, 0 }, /* 0x0608 */
+ { 0x0609, 0 }, /* 0x0609 */
+ { 0x060A, 0 }, /* 0x060A */
+ { 0x060B, 0 }, /* 0x060B */
+ { 0x060C, 0 }, /* 0x060C */
+ { 0x060D, 0 }, /* 0x060D */
+ { 0x060E, 0 }, /* 0x060E */
+ { 0x060F, 0 }, /* 0x060F */
+
+ { 0x0610, 0 }, /* 0x0610 */
+ { 0x0611, 0 }, /* 0x0611 */
+ { 0x0612, 0 }, /* 0x0612 */
+ { 0x0613, 0 }, /* 0x0613 */
+ { 0x0614, 0 }, /* 0x0614 */
+ { 0x0615, 0 }, /* 0x0615 */
+ { 0x0616, 0 }, /* 0x0616 */
+ { 0x0617, 0 }, /* 0x0617 */
+ { 0x0618, 0 }, /* 0x0618 */
+ { 0x0619, 0 }, /* 0x0619 */
+ { 0x061A, 0 }, /* 0x061A */
+ { 0x061B, 0 }, /* 0x061B */
+ { 0x061C, 0 }, /* 0x061C */
+ { 0x061D, 0 }, /* 0x061D */
+ { 0x061E, 0 }, /* 0x061E */
+ { 0x061F, 0 }, /* 0x061F */
+
+ { 0x0620, 0 }, /* 0x0620 */
+ { 0xFE80, 0 }, /* 0x0621 HAMZA */
+ { 0xFE81, 1 }, /* 0x0622 R ALEF WITH MADDA ABOVE */
+ { 0xFE83, 1 }, /* 0x0623 R ALEF WITH HAMZA ABOVE */
+ { 0xFE85, 1 }, /* 0x0624 R WAW WITH HAMZA ABOVE */
+ { 0xFE87, 1 }, /* 0x0625 R ALEF WITH HAMZA BELOW */
+ { 0xFE89, 3 }, /* 0x0626 D YEH WITH HAMZA ABOVE */
+ { 0xFE8D, 1 }, /* 0x0627 R ALEF */
+ { 0xFE8F, 3 }, /* 0x0628 D BEH */
+ { 0xFE93, 1 }, /* 0x0629 R TEH MARBUTA */
+ { 0xFE95, 3 }, /* 0x062A D TEH */
+ { 0xFE99, 3 }, /* 0x062B D THEH */
+ { 0xFE9D, 3 }, /* 0x062C D JEEM */
+ { 0xFEA1, 3 }, /* 0x062D D HAH */
+ { 0xFEA5, 3 }, /* 0x062E D KHAH */
+ { 0xFEA9, 1 }, /* 0x062F R DAL */
+
+ { 0xFEAB, 1 }, /* 0x0630 R THAL */
+ { 0xFEAD, 1 }, /* 0x0631 R REH */
+ { 0xFEAF, 1 }, /* 0x0632 R ZAIN */
+ { 0xFEB1, 3 }, /* 0x0633 D SEEN */
+ { 0xFEB5, 3 }, /* 0x0634 D SHEEN */
+ { 0xFEB9, 3 }, /* 0x0635 D SAD */
+ { 0xFEBD, 3 }, /* 0x0636 D DAD */
+ { 0xFEC1, 3 }, /* 0x0637 D TAH */
+ { 0xFEC5, 3 }, /* 0x0638 D ZAH */
+ { 0xFEC9, 3 }, /* 0x0639 D AIN */
+ { 0xFECD, 3 }, /* 0x063A D GHAIN */
+ { 0x063B, 0 }, /* 0x063B */
+ { 0x063C, 0 }, /* 0x063C */
+ { 0x063D, 0 }, /* 0x063D */
+ { 0x063E, 0 }, /* 0x063E */
+ { 0x063F, 0 }, /* 0x063F */
+
+ { 0x0640, 0 }, /* 0x0640 C TATWEEL // ### Join Causing, only one glyph */
+ { 0xFED1, 3 }, /* 0x0641 D FEH */
+ { 0xFED5, 3 }, /* 0x0642 D QAF */
+ { 0xFED9, 3 }, /* 0x0643 D KAF */
+ { 0xFEDD, 3 }, /* 0x0644 D LAM */
+ { 0xFEE1, 3 }, /* 0x0645 D MEEM */
+ { 0xFEE5, 3 }, /* 0x0646 D NOON */
+ { 0xFEE9, 3 }, /* 0x0647 D HEH */
+ { 0xFEED, 1 }, /* 0x0648 R WAW */
+ { 0x0649, 3 }, /* 0x0649 ALEF MAKSURA // ### Dual, glyphs not consecutive, handle in code. */
+ { 0xFEF1, 3 }, /* 0x064A D YEH */
+ { 0x064B, 0 }, /* 0x064B */
+ { 0x064C, 0 }, /* 0x064C */
+ { 0x064D, 0 }, /* 0x064D */
+ { 0x064E, 0 }, /* 0x064E */
+ { 0x064F, 0 }, /* 0x064F */
+
+ { 0x0650, 0 }, /* 0x0650 */
+ { 0x0651, 0 }, /* 0x0651 */
+ { 0x0652, 0 }, /* 0x0652 */
+ { 0x0653, 0 }, /* 0x0653 */
+ { 0x0654, 0 }, /* 0x0654 */
+ { 0x0655, 0 }, /* 0x0655 */
+ { 0x0656, 0 }, /* 0x0656 */
+ { 0x0657, 0 }, /* 0x0657 */
+ { 0x0658, 0 }, /* 0x0658 */
+ { 0x0659, 0 }, /* 0x0659 */
+ { 0x065A, 0 }, /* 0x065A */
+ { 0x065B, 0 }, /* 0x065B */
+ { 0x065C, 0 }, /* 0x065C */
+ { 0x065D, 0 }, /* 0x065D */
+ { 0x065E, 0 }, /* 0x065E */
+ { 0x065F, 0 }, /* 0x065F */
+
+ { 0x0660, 0 }, /* 0x0660 */
+ { 0x0661, 0 }, /* 0x0661 */
+ { 0x0662, 0 }, /* 0x0662 */
+ { 0x0663, 0 }, /* 0x0663 */
+ { 0x0664, 0 }, /* 0x0664 */
+ { 0x0665, 0 }, /* 0x0665 */
+ { 0x0666, 0 }, /* 0x0666 */
+ { 0x0667, 0 }, /* 0x0667 */
+ { 0x0668, 0 }, /* 0x0668 */
+ { 0x0669, 0 }, /* 0x0669 */
+ { 0x066A, 0 }, /* 0x066A */
+ { 0x066B, 0 }, /* 0x066B */
+ { 0x066C, 0 }, /* 0x066C */
+ { 0x066D, 0 }, /* 0x066D */
+ { 0x066E, 0 }, /* 0x066E */
+ { 0x066F, 0 }, /* 0x066F */
+
+ { 0x0670, 0 }, /* 0x0670 */
+ { 0xFB50, 1 }, /* 0x0671 R ALEF WASLA */
+ { 0x0672, 0 }, /* 0x0672 */
+ { 0x0673, 0 }, /* 0x0673 */
+ { 0x0674, 0 }, /* 0x0674 */
+ { 0x0675, 0 }, /* 0x0675 */
+ { 0x0676, 0 }, /* 0x0676 */
+ { 0x0677, 0 }, /* 0x0677 */
+ { 0x0678, 0 }, /* 0x0678 */
+ { 0xFB66, 3 }, /* 0x0679 D TTEH */
+ { 0xFB5E, 3 }, /* 0x067A D TTEHEH */
+ { 0xFB52, 3 }, /* 0x067B D BEEH */
+ { 0x067C, 0 }, /* 0x067C */
+ { 0x067D, 0 }, /* 0x067D */
+ { 0xFB56, 3 }, /* 0x067E D PEH */
+ { 0xFB62, 3 }, /* 0x067F D TEHEH */
+
+ { 0xFB5A, 3 }, /* 0x0680 D BEHEH */
+ { 0x0681, 0 }, /* 0x0681 */
+ { 0x0682, 0 }, /* 0x0682 */
+ { 0xFB76, 3 }, /* 0x0683 D NYEH */
+ { 0xFB72, 3 }, /* 0x0684 D DYEH */
+ { 0x0685, 0 }, /* 0x0685 */
+ { 0xFB7A, 3 }, /* 0x0686 D TCHEH */
+ { 0xFB7E, 3 }, /* 0x0687 D TCHEHEH */
+ { 0xFB88, 1 }, /* 0x0688 R DDAL */
+ { 0x0689, 0 }, /* 0x0689 */
+ { 0x068A, 0 }, /* 0x068A */
+ { 0x068B, 0 }, /* 0x068B */
+ { 0xFB84, 1 }, /* 0x068C R DAHAL */
+ { 0xFB82, 1 }, /* 0x068D R DDAHAL */
+ { 0xFB86, 1 }, /* 0x068E R DUL */
+ { 0x068F, 0 }, /* 0x068F */
+
+ { 0x0690, 0 }, /* 0x0690 */
+ { 0xFB8C, 1 }, /* 0x0691 R RREH */
+ { 0x0692, 0 }, /* 0x0692 */
+ { 0x0693, 0 }, /* 0x0693 */
+ { 0x0694, 0 }, /* 0x0694 */
+ { 0x0695, 0 }, /* 0x0695 */
+ { 0x0696, 0 }, /* 0x0696 */
+ { 0x0697, 0 }, /* 0x0697 */
+ { 0xFB8A, 1 }, /* 0x0698 R JEH */
+ { 0x0699, 0 }, /* 0x0699 */
+ { 0x069A, 0 }, /* 0x069A */
+ { 0x069B, 0 }, /* 0x069B */
+ { 0x069C, 0 }, /* 0x069C */
+ { 0x069D, 0 }, /* 0x069D */
+ { 0x069E, 0 }, /* 0x069E */
+ { 0x069F, 0 }, /* 0x069F */
+
+ { 0x06A0, 0 }, /* 0x06A0 */
+ { 0x06A1, 0 }, /* 0x06A1 */
+ { 0x06A2, 0 }, /* 0x06A2 */
+ { 0x06A3, 0 }, /* 0x06A3 */
+ { 0xFB6A, 3 }, /* 0x06A4 D VEH */
+ { 0x06A5, 0 }, /* 0x06A5 */
+ { 0xFB6E, 3 }, /* 0x06A6 D PEHEH */
+ { 0x06A7, 0 }, /* 0x06A7 */
+ { 0x06A8, 0 }, /* 0x06A8 */
+ { 0xFB8E, 3 }, /* 0x06A9 D KEHEH */
+ { 0x06AA, 0 }, /* 0x06AA */
+ { 0x06AB, 0 }, /* 0x06AB */
+ { 0x06AC, 0 }, /* 0x06AC */
+ { 0xFBD3, 3 }, /* 0x06AD D NG */
+ { 0x06AE, 0 }, /* 0x06AE */
+ { 0xFB92, 3 }, /* 0x06AF D GAF */
+
+ { 0x06B0, 0 }, /* 0x06B0 */
+ { 0xFB9A, 3 }, /* 0x06B1 D NGOEH */
+ { 0x06B2, 0 }, /* 0x06B2 */
+ { 0xFB96, 3 }, /* 0x06B3 D GUEH */
+ { 0x06B4, 0 }, /* 0x06B4 */
+ { 0x06B5, 0 }, /* 0x06B5 */
+ { 0x06B6, 0 }, /* 0x06B6 */
+ { 0x06B7, 0 }, /* 0x06B7 */
+ { 0x06B8, 0 }, /* 0x06B8 */
+ { 0x06B9, 0 }, /* 0x06B9 */
+ { 0xFB9E, 1 }, /* 0x06BA R NOON GHUNNA */
+ { 0xFBA0, 3 }, /* 0x06BB D RNOON */
+ { 0x06BC, 0 }, /* 0x06BC */
+ { 0x06BD, 0 }, /* 0x06BD */
+ { 0xFBAA, 3 }, /* 0x06BE D HEH DOACHASHMEE */
+ { 0x06BF, 0 }, /* 0x06BF */
+
+ { 0xFBA4, 1 }, /* 0x06C0 R HEH WITH YEH ABOVE */
+ { 0xFBA6, 3 }, /* 0x06C1 D HEH GOAL */
+ { 0x06C2, 0 }, /* 0x06C2 */
+ { 0x06C3, 0 }, /* 0x06C3 */
+ { 0x06C4, 0 }, /* 0x06C4 */
+ { 0xFBE0, 1 }, /* 0x06C5 R KIRGHIZ OE */
+ { 0xFBD9, 1 }, /* 0x06C6 R OE */
+ { 0xFBD7, 1 }, /* 0x06C7 R U */
+ { 0xFBDB, 1 }, /* 0x06C8 R YU */
+ { 0xFBE2, 1 }, /* 0x06C9 R KIRGHIZ YU */
+ { 0x06CA, 0 }, /* 0x06CA */
+ { 0xFBDE, 1 }, /* 0x06CB R VE */
+ { 0xFBFC, 3 }, /* 0x06CC D FARSI YEH */
+ { 0x06CD, 0 }, /* 0x06CD */
+ { 0x06CE, 0 }, /* 0x06CE */
+ { 0x06CF, 0 }, /* 0x06CF */
+
+ { 0xFBE4, 3 }, /* 0x06D0 D E */
+ { 0x06D1, 0 }, /* 0x06D1 */
+ { 0xFBAE, 1 }, /* 0x06D2 R YEH BARREE */
+ { 0xFBB0, 1 }, /* 0x06D3 R YEH BARREE WITH HAMZA ABOVE */
+ { 0x06D4, 0 }, /* 0x06D4 */
+ { 0x06D5, 0 }, /* 0x06D5 */
+ { 0x06D6, 0 }, /* 0x06D6 */
+ { 0x06D7, 0 }, /* 0x06D7 */
+ { 0x06D8, 0 }, /* 0x06D8 */
+ { 0x06D9, 0 }, /* 0x06D9 */
+ { 0x06DA, 0 }, /* 0x06DA */
+ { 0x06DB, 0 }, /* 0x06DB */
+ { 0x06DC, 0 }, /* 0x06DC */
+ { 0x06DD, 0 }, /* 0x06DD */
+ { 0x06DE, 0 }, /* 0x06DE */
+ { 0x06DF, 0 }, /* 0x06DF */
+
+ { 0x06E0, 0 }, /* 0x06E0 */
+ { 0x06E1, 0 }, /* 0x06E1 */
+ { 0x06E2, 0 }, /* 0x06E2 */
+ { 0x06E3, 0 }, /* 0x06E3 */
+ { 0x06E4, 0 }, /* 0x06E4 */
+ { 0x06E5, 0 }, /* 0x06E5 */
+ { 0x06E6, 0 }, /* 0x06E6 */
+ { 0x06E7, 0 }, /* 0x06E7 */
+ { 0x06E8, 0 }, /* 0x06E8 */
+ { 0x06E9, 0 }, /* 0x06E9 */
+ { 0x06EA, 0 }, /* 0x06EA */
+ { 0x06EB, 0 }, /* 0x06EB */
+ { 0x06EC, 0 }, /* 0x06EC */
+ { 0x06ED, 0 }, /* 0x06ED */
+ { 0x06EE, 0 }, /* 0x06EE */
+ { 0x06EF, 0 }, /* 0x06EF */
+
+ { 0x06F0, 0 }, /* 0x06F0 */
+ { 0x06F1, 0 }, /* 0x06F1 */
+ { 0x06F2, 0 }, /* 0x06F2 */
+ { 0x06F3, 0 }, /* 0x06F3 */
+ { 0x06F4, 0 }, /* 0x06F4 */
+ { 0x06F5, 0 }, /* 0x06F5 */
+ { 0x06F6, 0 }, /* 0x06F6 */
+ { 0x06F7, 0 }, /* 0x06F7 */
+ { 0x06F8, 0 }, /* 0x06F8 */
+ { 0x06F9, 0 }, /* 0x06F9 */
+ { 0x06FA, 0 }, /* 0x06FA */
+ { 0x06FB, 0 }, /* 0x06FB */
+ { 0x06FC, 0 }, /* 0x06FC */
+ { 0x06FD, 0 }, /* 0x06FD */
+ { 0x06FE, 0 }, /* 0x06FE */
+ { 0x06FF, 0 } /* 0x06FF */
+};
+
+/* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, this table does */
+static const hb_uint16 alefMaksura[4] = {0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9};
+
+/*
+// this is a bit tricky. Alef always binds to the right, so the second parameter descibing the shape
+// of the lam can be either initial of medial. So initial maps to the isolated form of the ligature,
+// medial to the final form
+*/
+static const hb_uint16 arabicUnicodeLamAlefMapping[6][4] = {
+ { 0xfffd, 0xfffd, 0xfef5, 0xfef6 }, /* 0x622 R Alef with Madda above */
+ { 0xfffd, 0xfffd, 0xfef7, 0xfef8 }, /* 0x623 R Alef with Hamza above */
+ { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x624 // Just to fill the table ;-) */
+ { 0xfffd, 0xfffd, 0xfef9, 0xfefa }, /* 0x625 R Alef with Hamza below */
+ { 0xfffd, 0xfffd, 0xfffd, 0xfffd }, /* 0x626 // Just to fill the table ;-) */
+ { 0xfffd, 0xfffd, 0xfefb, 0xfefc } /* 0x627 R Alef */
+};
+
+static int getShape(hb_uint8 cell, int shape)
+{
+ /* the arabicUnicodeMapping does not work for U+0649 ALEF MAKSURA, handle this here */
+ int ch = (cell != 0x49)
+ ? (shape ? arabicUnicodeMapping[cell][0] + shape : 0x600+cell)
+ : alefMaksura[shape] ;
+ return ch;
+}
+
+
+/*
+ Two small helper functions for arabic shaping.
+*/
+static HB_UChar16 prevChar(const HB_UChar16 *str, int pos)
+{
+ /*qDebug("leftChar: pos=%d", pos); */
+ const HB_UChar16 *ch = str + pos - 1;
+ pos--;
+ while(pos > -1) {
+ if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing)
+ return *ch;
+ pos--;
+ ch--;
+ }
+ return ReplacementCharacter;
+}
+
+static HB_UChar16 nextChar(const HB_UChar16 *str, hb_uint32 len, hb_uint32 pos)
+{
+ const HB_UChar16 *ch = str + pos + 1;
+ pos++;
+ while(pos < len) {
+ /*qDebug("rightChar: %d isLetter=%d, joining=%d", pos, ch.isLetter(), ch.joining()); */
+ if(HB_GetUnicodeCharCategory(*ch) != HB_Mark_NonSpacing)
+ return *ch;
+ /* assume it's a transparent char, this might not be 100% correct */
+ pos++;
+ ch++;
+ }
+ return ReplacementCharacter;
+}
+
+static void shapedString(const HB_UChar16 *uc, hb_uint32 stringLength, hb_uint32 from, hb_uint32 len, HB_UChar16 *shapeBuffer, int *shapedLength,
+ HB_Bool reverse, HB_GlyphAttributes *attributes, unsigned short *logClusters)
+{
+ HB_ArabicProperties *properties;
+ hb_int32 f = from;
+ hb_uint32 l = len;
+ const HB_UChar16 *ch;
+ HB_UChar16 *data;
+ int clusterStart;
+ hb_uint32 i;
+ HB_STACKARRAY(HB_ArabicProperties, props, len + 2);
+ properties = props;
+
+ assert(stringLength >= from + len);
+
+ if(len == 0) {
+ *shapedLength = 0;
+ return;
+ }
+
+ if (from > 0) {
+ --f;
+ ++l;
+ ++properties;
+ }
+ if (f + l < stringLength)
+ ++l;
+ getArabicProperties(uc+f, l, props);
+
+ ch = uc + from;
+ data = shapeBuffer;
+ clusterStart = 0;
+
+ for (i = 0; i < len; i++) {
+ hb_uint8 r = *ch >> 8;
+ int gpos = data - shapeBuffer;
+
+ if (r != 0x06) {
+ if (r == 0x20) {
+ if (*ch == 0x200c || *ch == 0x200d)
+ /* remove ZWJ and ZWNJ */
+ goto skip;
+ }
+ if (reverse)
+ *data = HB_GetMirroredChar(*ch);
+ else
+ *data = *ch;
+ } else {
+ hb_uint8 c = *ch & 0xff;
+ int pos = i + from;
+ int shape = properties[i].shape;
+/* qDebug("mapping U+%x to shape %d glyph=0x%x", ch->unicode(), shape, getShape(c, shape)); */
+ /* take care of lam-alef ligatures (lam right of alef) */
+ hb_uint16 map;
+ switch (c) {
+ case 0x44: { /* lam */
+ const HB_UChar16 pch = nextChar(uc, stringLength, pos);
+ if ((pch >> 8) == 0x06) {
+ switch (pch & 0xff) {
+ case 0x22:
+ case 0x23:
+ case 0x25:
+ case 0x27:
+/* qDebug(" lam of lam-alef ligature"); */
+ map = arabicUnicodeLamAlefMapping[(pch & 0xff) - 0x22][shape];
+ goto next;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case 0x22: /* alef with madda */
+ case 0x23: /* alef with hamza above */
+ case 0x25: /* alef with hamza below */
+ case 0x27: /* alef */
+ if (prevChar(uc, pos) == 0x0644) {
+ /* have a lam alef ligature */
+ /*qDebug(" alef of lam-alef ligature"); */
+ goto skip;
+ }
+ default:
+ break;
+ }
+ map = getShape(c, shape);
+ next:
+ *data = map;
+ }
+ /* ##### Fixme */
+ /*glyphs[gpos].attributes.zeroWidth = zeroWidth; */
+ if (HB_GetUnicodeCharCategory(*ch) == HB_Mark_NonSpacing) {
+ attributes[gpos].mark = TRUE;
+/* qDebug("glyph %d (char %d) is mark!", gpos, i); */
+ } else {
+ attributes[gpos].mark = FALSE;
+ clusterStart = data - shapeBuffer;
+ }
+ attributes[gpos].clusterStart = !attributes[gpos].mark;
+ attributes[gpos].combiningClass = HB_GetUnicodeCharCombiningClass(*ch);
+ attributes[gpos].justification = properties[i].justification;
+/* qDebug("data[%d] = %x (from %x)", gpos, (uint)data->unicode(), ch->unicode());*/
+ data++;
+ skip:
+ ch++;
+ logClusters[i] = clusterStart;
+ }
+ *shapedLength = data - shapeBuffer;
+
+ HB_FREE_STACKARRAY(props);
+}
+
+#ifndef NO_OPENTYPE
+
+static const HB_OpenTypeFeature arabic_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty },
+ { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty },
+ { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty },
+ { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty },
+ { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty },
+ { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
+ { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty },
+ { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty },
+ { HB_MAKE_TAG('c', 's', 'w', 'h'), CswhProperty },
+ /* mset is used in old Win95 fonts that don't have a 'mark' positioning table. */
+ { HB_MAKE_TAG('m', 's', 'e', 't'), MsetProperty },
+ {0, 0}
+};
+
+static const HB_OpenTypeFeature syriac_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('i', 's', 'o', 'l'), IsolProperty },
+ { HB_MAKE_TAG('f', 'i', 'n', 'a'), FinaProperty },
+ { HB_MAKE_TAG('f', 'i', 'n', '2'), FinaProperty },
+ { HB_MAKE_TAG('f', 'i', 'n', '3'), FinaProperty },
+ { HB_MAKE_TAG('m', 'e', 'd', 'i'), MediProperty },
+ { HB_MAKE_TAG('m', 'e', 'd', '2'), MediProperty },
+ { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty },
+ { HB_MAKE_TAG('r', 'l', 'i', 'g'), RligProperty },
+ { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
+ { HB_MAKE_TAG('l', 'i', 'g', 'a'), LigaProperty },
+ { HB_MAKE_TAG('d', 'l', 'i', 'g'), DligProperty },
+ {0, 0}
+};
+
+static HB_Bool arabicSyriacOpenTypeShape(HB_ShaperItem *item, HB_Bool *ot_ok)
+{
+ const HB_UChar16 *uc;
+ const int nglyphs = item->num_glyphs;
+ hb_int32 f;
+ hb_uint32 l;
+ HB_ArabicProperties *properties;
+ HB_DECLARE_STACKARRAY(HB_ArabicProperties, props)
+ HB_DECLARE_STACKARRAY(hb_uint32, apply)
+ HB_Bool shaped;
+ int i = 0;
+
+ *ot_ok = TRUE;
+
+ if (!HB_ConvertStringToGlyphIndices(item))
+ return FALSE;
+ HB_HeuristicSetGlyphAttributes(item);
+
+ HB_INIT_STACKARRAY(HB_ArabicProperties, props, item->item.length + 2);
+ HB_INIT_STACKARRAY(hb_uint32, apply, item->num_glyphs);
+
+ uc = item->string + item->item.pos;
+
+ properties = props;
+ f = 0;
+ l = item->item.length;
+ if (item->item.pos > 0) {
+ --f;
+ ++l;
+ ++properties;
+ }
+ if (f + l < item->stringLength) {
+ ++l;
+ }
+ getArabicProperties(uc+f, l, props);
+
+ for (i = 0; i < (int)item->num_glyphs; i++) {
+ apply[i] = 0;
+
+ if (properties[i].shape == XIsolated)
+ apply[i] |= MediProperty|FinaProperty|InitProperty;
+ else if (properties[i].shape == XMedial)
+ apply[i] |= IsolProperty|FinaProperty|InitProperty;
+ else if (properties[i].shape == XFinal)
+ apply[i] |= IsolProperty|MediProperty|InitProperty;
+ else if (properties[i].shape == XInitial)
+ apply[i] |= IsolProperty|MediProperty|FinaProperty;
+
+ item->attributes[i].justification = properties[i].justification;
+ }
+
+ HB_FREE_STACKARRAY(props);
+
+ shaped = HB_OpenTypeShape(item, apply);
+
+ HB_FREE_STACKARRAY(apply);
+
+ if (!shaped) {
+ *ot_ok = FALSE;
+ return FALSE;
+ }
+ return HB_OpenTypePosition(item, nglyphs, /*doLogClusters*/TRUE);
+}
+
+#endif
+
+/* #### stil missing: identify invalid character combinations */
+HB_Bool HB_ArabicShape(HB_ShaperItem *item)
+{
+ int slen;
+ HB_Bool haveGlyphs;
+ HB_STACKARRAY(HB_UChar16, shapedChars, item->item.length);
+
+ assert(item->item.script == HB_Script_Arabic || item->item.script == HB_Script_Syriac);
+
+#ifndef NO_OPENTYPE
+
+ if (HB_SelectScript(item, item->item.script == HB_Script_Arabic ? arabic_features : syriac_features)) {
+ HB_Bool ot_ok;
+ if (arabicSyriacOpenTypeShape(item, &ot_ok))
+ return TRUE;
+ if (ot_ok)
+ return FALSE;
+ /* fall through to the non OT code*/
+ }
+#endif
+
+ if (item->item.script == HB_Script_Syriac)
+ return HB_BasicShape(item);
+
+ shapedString(item->string, item->stringLength, item->item.pos, item->item.length, shapedChars, &slen,
+ item->item.bidiLevel % 2,
+ item->attributes, item->log_clusters);
+
+ haveGlyphs = item->font->klass
+ ->convertStringToGlyphIndices(item->font,
+ shapedChars, slen,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2);
+
+ HB_FREE_STACKARRAY(shapedChars);
+
+ if (!haveGlyphs)
+ return FALSE;
+
+ HB_HeuristicPosition(item);
+ return TRUE;
+}
+
+
diff --git a/third_party/harfbuzz/src/harfbuzz-buffer-private.h b/third_party/harfbuzz/src/harfbuzz-buffer-private.h
new file mode 100644
index 0000000..5065f2e
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-buffer-private.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HARFBUZZ_BUFFER_PRIVATE_H
+#define HARFBUZZ_BUFFER_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+#define HB_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
+
+HB_INTERNAL void
+_hb_buffer_swap( HB_Buffer buffer );
+
+HB_INTERNAL void
+_hb_buffer_clear_output( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_clear_positions( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyphs( HB_Buffer buffer,
+ HB_UShort num_in,
+ HB_UShort num_out,
+ HB_UShort *glyph_data,
+ HB_UShort component,
+ HB_UShort ligID );
+
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyph ( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_UShort component,
+ HB_UShort ligID );
+
+HB_INTERNAL HB_Error
+_hb_buffer_copy_output_glyph ( HB_Buffer buffer );
+
+HB_INTERNAL HB_Error
+_hb_buffer_replace_output_glyph ( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_Bool inplace );
+
+HB_INTERNAL HB_UShort
+_hb_buffer_allocate_ligid( HB_Buffer buffer );
+
+
+/* convenience macros */
+
+#define IN_GLYPH( pos ) (buffer->in_string[(pos)].gindex)
+#define IN_ITEM( pos ) (&buffer->in_string[(pos)])
+#define IN_CURGLYPH() (buffer->in_string[buffer->in_pos].gindex)
+#define IN_CURITEM() (&buffer->in_string[buffer->in_pos])
+#define IN_PROPERTIES( pos ) (buffer->in_string[(pos)].properties)
+#define IN_LIGID( pos ) (buffer->in_string[(pos)].ligID)
+#define IN_COMPONENT( pos ) (buffer->in_string[(pos)].component)
+#define POSITION( pos ) (&buffer->positions[(pos)])
+#define OUT_GLYPH( pos ) (buffer->out_string[(pos)].gindex)
+#define OUT_ITEM( pos ) (&buffer->out_string[(pos)])
+
+#define CHECK_Property( gdef, index, flags, property ) \
+ ( ( error = _HB_GDEF_Check_Property( (gdef), (index), (flags), \
+ (property) ) ) != HB_Err_Ok )
+
+#define ADD_String( buffer, num_in, num_out, glyph_data, component, ligID ) \
+ ( ( error = _hb_buffer_add_output_glyphs( (buffer), \
+ (num_in), (num_out), \
+ (glyph_data), (component), (ligID) \
+ ) ) != HB_Err_Ok )
+#define ADD_Glyph( buffer, glyph_index, component, ligID ) \
+ ( ( error = _hb_buffer_add_output_glyph( (buffer), \
+ (glyph_index), (component), (ligID) \
+ ) ) != HB_Err_Ok )
+#define REPLACE_Glyph( buffer, glyph_index, nesting_level ) \
+ ( ( error = _hb_buffer_replace_output_glyph( (buffer), (glyph_index), \
+ (nesting_level) == 1 ) ) != HB_Err_Ok )
+#define COPY_Glyph( buffer ) \
+ ( (error = _hb_buffer_copy_output_glyph ( buffer ) ) != HB_Err_Ok )
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_BUFFER_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-buffer.c b/third_party/harfbuzz/src/harfbuzz-buffer.c
new file mode 100644
index 0000000..4d4c167
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-buffer.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-buffer-private.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+
+/* Here is how the buffer works internally:
+ *
+ * There are two string pointers: in_string and out_string. They
+ * always have same allocated size, but different length and positions.
+ *
+ * As an optimization, both in_string and out_string may point to the
+ * same piece of memory, which is owned by in_string. This remains the
+ * case as long as:
+ *
+ * - copy_glyph() is called
+ * - replace_glyph() is called with inplace=TRUE
+ * - add_output_glyph() and add_output_glyphs() are not called
+ *
+ * In that case swap(), and copy_glyph(), and replace_glyph() are all
+ * mostly no-op.
+ *
+ * As soon an add_output_glyph[s]() or replace_glyph() with inplace=FALSE is
+ * called, out_string is moved over to an alternate buffer (alt_string), and
+ * its current contents (out_length entries) are copied to the alt buffer.
+ * This should all remain transparent to the user. swap() then switches
+ * in_string and alt_string. alt_string is not allocated until its needed,
+ * but after that it's grown with in_string unconditionally.
+ *
+ * The buffer->separate_out boolean keeps status of whether out_string points
+ * to in_string (FALSE) or alt_string (TRUE).
+ */
+
+/* Internal API */
+
+static HB_Error
+hb_buffer_ensure( HB_Buffer buffer,
+ HB_UInt size )
+{
+ HB_UInt new_allocated = buffer->allocated;
+
+ if (size > new_allocated)
+ {
+ HB_Error error;
+
+ while (size > new_allocated)
+ new_allocated += (new_allocated >> 1) + 8;
+
+ if ( buffer->positions )
+ {
+ if ( REALLOC_ARRAY( buffer->positions, new_allocated, HB_PositionRec ) )
+ return error;
+ }
+
+ if ( REALLOC_ARRAY( buffer->in_string, new_allocated, HB_GlyphItemRec ) )
+ return error;
+
+ if ( buffer->separate_out )
+ {
+ if ( REALLOC_ARRAY( buffer->alt_string, new_allocated, HB_GlyphItemRec ) )
+ return error;
+
+ buffer->out_string = buffer->alt_string;
+ }
+ else
+ {
+ buffer->out_string = buffer->in_string;
+
+ if ( buffer->alt_string )
+ {
+ if ( REALLOC_ARRAY( buffer->alt_string, new_allocated, HB_GlyphItemRec ) )
+ return error;
+ }
+ }
+
+ buffer->allocated = new_allocated;
+ }
+
+ return HB_Err_Ok;
+}
+
+static HB_Error
+hb_buffer_duplicate_out_buffer( HB_Buffer buffer )
+{
+ if ( !buffer->alt_string )
+ {
+ HB_Error error;
+
+ if ( ALLOC_ARRAY( buffer->alt_string, buffer->allocated, HB_GlyphItemRec ) )
+ return error;
+ }
+
+ buffer->out_string = buffer->alt_string;
+ memcpy( buffer->out_string, buffer->in_string, buffer->out_length * sizeof (buffer->out_string[0]) );
+ buffer->separate_out = TRUE;
+
+ return HB_Err_Ok;
+}
+
+/* Public API */
+
+HB_Error
+hb_buffer_new( HB_Buffer *pbuffer )
+{
+ HB_Buffer buffer;
+ HB_Error error;
+
+ if ( ALLOC( buffer, sizeof( HB_BufferRec ) ) )
+ return error;
+
+ buffer->allocated = 0;
+ buffer->in_string = NULL;
+ buffer->alt_string = NULL;
+ buffer->positions = NULL;
+
+ hb_buffer_clear( buffer );
+
+ *pbuffer = buffer;
+
+ return HB_Err_Ok;
+}
+
+void
+hb_buffer_free( HB_Buffer buffer )
+{
+ FREE( buffer->in_string );
+ FREE( buffer->alt_string );
+ buffer->out_string = NULL;
+ FREE( buffer->positions );
+ FREE( buffer );
+}
+
+void
+hb_buffer_clear( HB_Buffer buffer )
+{
+ buffer->in_length = 0;
+ buffer->out_length = 0;
+ buffer->in_pos = 0;
+ buffer->out_pos = 0;
+ buffer->out_string = buffer->in_string;
+ buffer->separate_out = FALSE;
+ buffer->max_ligID = 0;
+}
+
+HB_Error
+hb_buffer_add_glyph( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_UInt properties,
+ HB_UInt cluster )
+{
+ HB_Error error;
+ HB_GlyphItem glyph;
+
+ error = hb_buffer_ensure( buffer, buffer->in_length + 1 );
+ if ( error )
+ return error;
+
+ glyph = &buffer->in_string[buffer->in_length];
+ glyph->gindex = glyph_index;
+ glyph->properties = properties;
+ glyph->cluster = cluster;
+ glyph->component = 0;
+ glyph->ligID = 0;
+ glyph->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN;
+
+ buffer->in_length++;
+
+ return HB_Err_Ok;
+}
+
+/* HarfBuzz-Internal API */
+
+HB_INTERNAL void
+_hb_buffer_clear_output( HB_Buffer buffer )
+{
+ buffer->out_length = 0;
+ buffer->out_pos = 0;
+ buffer->out_string = buffer->in_string;
+ buffer->separate_out = FALSE;
+}
+
+HB_INTERNAL HB_Error
+_hb_buffer_clear_positions( HB_Buffer buffer )
+{
+ if ( !buffer->positions )
+ {
+ HB_Error error;
+
+ if ( ALLOC_ARRAY( buffer->positions, buffer->allocated, HB_PositionRec ) )
+ return error;
+ }
+
+ memset (buffer->positions, 0, sizeof (buffer->positions[0]) * buffer->in_length);
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL void
+_hb_buffer_swap( HB_Buffer buffer )
+{
+ HB_GlyphItem tmp_string;
+ int tmp_length;
+ int tmp_pos;
+
+ if ( buffer->separate_out )
+ {
+ tmp_string = buffer->in_string;
+ buffer->in_string = buffer->out_string;
+ buffer->out_string = tmp_string;
+ buffer->alt_string = buffer->out_string;
+ }
+
+ tmp_length = buffer->in_length;
+ buffer->in_length = buffer->out_length;
+ buffer->out_length = tmp_length;
+
+ tmp_pos = buffer->in_pos;
+ buffer->in_pos = buffer->out_pos;
+ buffer->out_pos = tmp_pos;
+}
+
+/* The following function copies `num_out' elements from `glyph_data'
+ to `buffer->out_string', advancing the in array pointer in the structure
+ by `num_in' elements, and the out array pointer by `num_out' elements.
+ Finally, it sets the `length' field of `out' equal to
+ `pos' of the `out' structure.
+
+ If `component' is 0xFFFF, the component value from buffer->in_pos
+ will copied `num_out' times, otherwise `component' itself will
+ be used to fill the `component' fields.
+
+ If `ligID' is 0xFFFF, the ligID value from buffer->in_pos
+ will copied `num_out' times, otherwise `ligID' itself will
+ be used to fill the `ligID' fields.
+
+ The properties for all replacement glyphs are taken
+ from the glyph at position `buffer->in_pos'.
+
+ The cluster value for the glyph at position buffer->in_pos is used
+ for all replacement glyphs */
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyphs( HB_Buffer buffer,
+ HB_UShort num_in,
+ HB_UShort num_out,
+ HB_UShort *glyph_data,
+ HB_UShort component,
+ HB_UShort ligID )
+{
+ HB_Error error;
+ HB_UShort i;
+ HB_UInt properties;
+ HB_UInt cluster;
+
+ error = hb_buffer_ensure( buffer, buffer->out_pos + num_out );
+ if ( error )
+ return error;
+
+ if ( !buffer->separate_out )
+ {
+ error = hb_buffer_duplicate_out_buffer( buffer );
+ if ( error )
+ return error;
+ }
+
+ properties = buffer->in_string[buffer->in_pos].properties;
+ cluster = buffer->in_string[buffer->in_pos].cluster;
+ if ( component == 0xFFFF )
+ component = buffer->in_string[buffer->in_pos].component;
+ if ( ligID == 0xFFFF )
+ ligID = buffer->in_string[buffer->in_pos].ligID;
+
+ for ( i = 0; i < num_out; i++ )
+ {
+ HB_GlyphItem item = &buffer->out_string[buffer->out_pos + i];
+
+ item->gindex = glyph_data[i];
+ item->properties = properties;
+ item->cluster = cluster;
+ item->component = component;
+ item->ligID = ligID;
+ item->gproperties = HB_GLYPH_PROPERTIES_UNKNOWN;
+ }
+
+ buffer->in_pos += num_in;
+ buffer->out_pos += num_out;
+
+ buffer->out_length = buffer->out_pos;
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_Error
+_hb_buffer_add_output_glyph( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_UShort component,
+ HB_UShort ligID )
+{
+ HB_UShort glyph_data = glyph_index;
+
+ return _hb_buffer_add_output_glyphs ( buffer, 1, 1,
+ &glyph_data, component, ligID );
+}
+
+HB_INTERNAL HB_Error
+_hb_buffer_copy_output_glyph ( HB_Buffer buffer )
+{
+ HB_Error error;
+
+ error = hb_buffer_ensure( buffer, buffer->out_pos + 1 );
+ if ( error )
+ return error;
+
+ if ( buffer->separate_out )
+ {
+ buffer->out_string[buffer->out_pos] = buffer->in_string[buffer->in_pos];
+ }
+
+ buffer->in_pos++;
+ buffer->out_pos++;
+ buffer->out_length = buffer->out_pos;
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_Error
+_hb_buffer_replace_output_glyph( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_Bool inplace )
+{
+
+ HB_Error error;
+
+ if ( inplace )
+ {
+ error = _hb_buffer_copy_output_glyph ( buffer );
+ if ( error )
+ return error;
+
+ buffer->out_string[buffer->out_pos-1].gindex = glyph_index;
+ }
+ else
+ {
+ return _hb_buffer_add_output_glyph( buffer, glyph_index, 0xFFFF, 0xFFFF );
+ }
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_UShort
+_hb_buffer_allocate_ligid( HB_Buffer buffer )
+{
+ buffer->max_ligID++;
+ if (HB_UNLIKELY (buffer->max_ligID == 0))
+ buffer->max_ligID++;
+
+ return buffer->max_ligID;
+}
diff --git a/third_party/harfbuzz/src/harfbuzz-buffer.h b/third_party/harfbuzz/src/harfbuzz-buffer.h
new file mode 100644
index 0000000..b134407
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-buffer.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HARFBUZZ_BUFFER_H
+#define HARFBUZZ_BUFFER_H
+
+#include "harfbuzz-global.h"
+
+HB_BEGIN_HEADER
+
+typedef struct HB_GlyphItemRec_ {
+ HB_UInt gindex;
+ HB_UInt properties;
+ HB_UInt cluster;
+ HB_UShort component;
+ HB_UShort ligID;
+ HB_UShort gproperties;
+} HB_GlyphItemRec, *HB_GlyphItem;
+
+typedef struct HB_PositionRec_ {
+ HB_Fixed x_pos;
+ HB_Fixed y_pos;
+ HB_Fixed x_advance;
+ HB_Fixed y_advance;
+ HB_UShort back; /* number of glyphs to go back
+ for drawing current glyph */
+ HB_Bool new_advance; /* if set, the advance width values are
+ absolute, i.e., they won't be
+ added to the original glyph's value
+ but rather replace them. */
+ HB_Short cursive_chain; /* character to which this connects,
+ may be positive or negative; used
+ only internally */
+} HB_PositionRec, *HB_Position;
+
+
+typedef struct HB_BufferRec_{
+ HB_UInt allocated;
+
+ HB_UInt in_length;
+ HB_UInt out_length;
+ HB_UInt in_pos;
+ HB_UInt out_pos;
+
+ HB_Bool separate_out;
+ HB_GlyphItem in_string;
+ HB_GlyphItem out_string;
+ HB_GlyphItem alt_string;
+ HB_Position positions;
+ HB_UShort max_ligID;
+} HB_BufferRec, *HB_Buffer;
+
+HB_Error
+hb_buffer_new( HB_Buffer *buffer );
+
+void
+hb_buffer_free( HB_Buffer buffer );
+
+void
+hb_buffer_clear( HB_Buffer buffer );
+
+HB_Error
+hb_buffer_add_glyph( HB_Buffer buffer,
+ HB_UInt glyph_index,
+ HB_UInt properties,
+ HB_UInt cluster );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_BUFFER_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-dump-main.c b/third_party/harfbuzz/src/harfbuzz-dump-main.c
new file mode 100644
index 0000000..dfb35fb
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-dump-main.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2000 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "harfbuzz.h"
+#include "harfbuzz-dump.h"
+
+#define N_ELEMENTS(arr) (sizeof(arr)/ sizeof((arr)[0]))
+
+static int
+croak (const char *situation, HB_Error error)
+{
+ fprintf (stderr, "%s: Error %d\n", situation, error);
+
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ HB_Error error;
+ FT_Library library;
+ HB_Font font;
+ HB_GSUB gsub;
+ HB_GPOS gpos;
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: harfbuzz-dump MYFONT.TTF\n");
+ exit(1);
+ }
+
+ if ((error = FT_Init_FreeType (&library)))
+ croak ("FT_Init_FreeType", error);
+
+ if ((error = FT_New_Face (library, argv[1], 0, &font)))
+ croak ("FT_New_Face", error);
+
+ printf ("<?xml version=\"1.0\"?>\n");
+ printf ("<OpenType>\n");
+
+ if (!(error = HB_Load_GSUB_Table (font, &gsub, NULL)))
+ {
+ HB_Dump_GSUB_Table (gsub, stdout);
+
+ if ((error = HB_Done_GSUB_Table (gsub)))
+ croak ("HB_Done_GSUB_Table", error);
+ }
+ else if (error != HB_Err_Not_Covered)
+ fprintf (stderr, "HB_Load_GSUB_Table: error 0x%x\n", error);
+
+ if (!(error = HB_Load_GPOS_Table (font, &gpos, NULL)))
+ {
+ HB_Dump_GPOS_Table (gpos, stdout);
+
+ if ((error = HB_Done_GPOS_Table (gpos)))
+ croak ("HB_Done_GPOS_Table", error);
+ }
+ else if (error != HB_Err_Not_Covered)
+ fprintf (stderr, "HB_Load_GPOS_Table: error 0x%x\n", error);
+
+ printf ("</OpenType>\n");
+
+ if ((error = FT_Done_Face (font)))
+ croak ("FT_Done_Face", error);
+
+ if ((error = FT_Done_FreeType (library)))
+ croak ("FT_Done_FreeType", error);
+
+ return 0;
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-dump.c b/third_party/harfbuzz/src/harfbuzz-dump.c
new file mode 100644
index 0000000..8c81da1
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-dump.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2000, 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-dump.h"
+#include "harfbuzz-gdef-private.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+#include "harfbuzz-open-private.h"
+#include <stdarg.h>
+
+#define DUMP(format) dump (stream, indent, format)
+#define DUMP1(format, arg1) dump (stream, indent, format, arg1)
+#define DUMP2(format, arg1, arg2) dump (stream, indent, format, arg1, arg2)
+#define DUMP3(format, arg1, arg2, arg3) dump (stream, indent, format, arg1, arg2, arg3)
+
+#define DUMP_FINT(strct,fld) dump (stream, indent, "<" #fld ">%d</" #fld ">\n", (strct)->fld)
+#define DUMP_FUINT(strct,fld) dump (stream, indent, "<" #fld ">%u</" #fld ">\n", (strct)->fld)
+#define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
+#define DUMP_FGLYPH(strct,fld) dump (stream, indent, "<" #fld ">%#06x</" #fld ">\n", (strct)->fld)
+#define DUMP_USHORT_ARRAY(strct,fld,cnt) Dump_UShort_Array ((strct)->fld, cnt, #fld, stream, indent);
+
+#define DEF_DUMP(type) static void Dump_ ## type (HB_ ## type *type, FILE *stream, int indent, HB_Type hb_type)
+#define RECURSE(name, type, val) do { DUMP ("<" #name ">\n"); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
+#define RECURSE_NUM(name, i, type, val) do { DUMP1 ("<" #name "> <!-- %d -->\n", i); Dump_ ## type (val, stream, indent + 1, hb_type); DUMP ("</" #name ">\n"); } while (0)
+#define DUMP_VALUE_RECORD(val, frmt) do { DUMP ("<ValueRecord>\n"); Dump_ValueRecord (val, stream, indent + 1, hb_type, frmt); DUMP ("</ValueRecord>\n"); } while (0)
+
+static void
+do_indent (FILE *stream, int indent)
+{
+ fprintf (stream, "%*s", indent * 3, "");
+}
+
+static void
+dump (FILE *stream, int indent, const char *format, ...)
+{
+ va_list list;
+
+ do_indent (stream, indent);
+
+ va_start (list, format);
+ vfprintf (stream, format, list);
+ va_end (list);
+}
+
+static void
+Dump_UShort_Array (HB_UShort *array, int count, const char *name, FILE *stream, int indent)
+{
+ int i;
+
+ do_indent (stream, indent);
+
+ fprintf (stream, "<%s>", name);
+ for (i = 0; i < count; i++)
+ fprintf (stream, "%d%s", array[i], i == 0 ? "" : " ");
+ fprintf (stream, "</%s>\n", name);
+}
+
+static void
+Print_Tag (HB_UInt tag, FILE *stream)
+{
+ fprintf (stream, "%c%c%c%c",
+ (unsigned char)(tag >> 24),
+ (unsigned char)((tag >> 16) & 0xff),
+ (unsigned char)((tag >> 8) & 0xff),
+ (unsigned char)(tag & 0xff));
+}
+
+DEF_DUMP (LangSys)
+{
+ int i;
+
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (LangSys, LookupOrderOffset);
+ DUMP_FUINT (LangSys, ReqFeatureIndex);
+ DUMP_FUINT (LangSys, FeatureCount);
+
+ for (i=0; i < LangSys->FeatureCount; i++)
+ DUMP1("<FeatureIndex>%d</FeatureIndex>\n", LangSys->FeatureIndex[i]);
+}
+
+DEF_DUMP (ScriptTable)
+{
+ int i;
+
+ RECURSE (DefaultLangSys, LangSys, &ScriptTable->DefaultLangSys);
+
+ DUMP_FUINT (ScriptTable, LangSysCount);
+
+ for (i=0; i < ScriptTable->LangSysCount; i++)
+ {
+ do_indent (stream, indent);
+ fprintf (stream, "<LangSysTag>");
+ Print_Tag (ScriptTable->LangSysRecord[i].LangSysTag, stream);
+ fprintf (stream, "</LangSysTag>\n");
+ RECURSE_NUM (LangSys, i, LangSys, &ScriptTable->LangSysRecord[i].LangSys);
+ }
+}
+
+DEF_DUMP (ScriptList)
+{
+ int i;
+
+ DUMP_FUINT (ScriptList, ScriptCount);
+
+ for (i=0; i < ScriptList->ScriptCount; i++)
+ {
+ do_indent (stream, indent);
+ fprintf (stream, "<ScriptTag>");
+ Print_Tag (ScriptList->ScriptRecord[i].ScriptTag, stream);
+ fprintf (stream, "</ScriptTag>\n");
+ RECURSE_NUM (Script, i, ScriptTable, &ScriptList->ScriptRecord[i].Script);
+ }
+}
+
+DEF_DUMP (Feature)
+{
+ int i;
+
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (Feature, FeatureParams);
+ DUMP_FUINT (Feature, LookupListCount);
+
+ for (i=0; i < Feature->LookupListCount; i++)
+ DUMP1("<LookupIndex>%d</LookupIndex>\n", Feature->LookupListIndex[i]);
+}
+
+DEF_DUMP (MarkRecord)
+{
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (MarkRecord, Class);
+ DUMP1("<Anchor>%d</Anchor>\n", MarkRecord->MarkAnchor.PosFormat );
+}
+
+DEF_DUMP (MarkArray)
+{
+ int i;
+
+ DUMP_FUINT (MarkArray, MarkCount);
+
+ for (i=0; i < MarkArray->MarkCount; i++)
+ RECURSE_NUM (MarkRecord, i, MarkRecord, &MarkArray->MarkRecord[i]);
+}
+
+DEF_DUMP (FeatureList)
+{
+ int i;
+
+ DUMP_FUINT (FeatureList, FeatureCount);
+
+ for (i=0; i < FeatureList->FeatureCount; i++)
+ {
+ do_indent (stream, indent);
+ fprintf (stream, "<FeatureTag>");
+ Print_Tag (FeatureList->FeatureRecord[i].FeatureTag, stream);
+ fprintf (stream, "</FeatureTag> <!-- %d -->\n", i);
+ RECURSE_NUM (Feature, i, Feature, &FeatureList->FeatureRecord[i].Feature);
+ }
+}
+
+DEF_DUMP (Coverage)
+{
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (Coverage, CoverageFormat);
+
+ if (Coverage->CoverageFormat == 1)
+ {
+ int i;
+ DUMP_FUINT (&Coverage->cf.cf1, GlyphCount);
+
+ for (i = 0; i < Coverage->cf.cf1.GlyphCount; i++)
+ DUMP2("<Glyph>%#06x</Glyph> <!-- %d -->\n",
+ Coverage->cf.cf1.GlyphArray[i], i);
+ }
+ else
+ {
+ int i;
+ DUMP_FUINT (&Coverage->cf.cf2, RangeCount);
+
+ for ( i = 0; i < Coverage->cf.cf2.RangeCount; i++ )
+ DUMP3("<Glyph>%#06x - %#06x</Glyph> <!-- %d -->\n",
+ Coverage->cf.cf2.RangeRecord[i].Start,
+ Coverage->cf.cf2.RangeRecord[i].End, i);
+ }
+}
+
+DEF_DUMP (ClassRangeRecord)
+{
+ HB_UNUSED(hb_type);
+
+ DUMP_FGLYPH (ClassRangeRecord, Start);
+ DUMP_FGLYPH (ClassRangeRecord, End);
+ DUMP_FUINT (ClassRangeRecord, Class);
+}
+
+DEF_DUMP (ClassDefinition)
+{
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT( ClassDefinition, ClassFormat);
+ DUMP_FUINT( ClassDefinition, loaded);
+
+ if (ClassDefinition->ClassFormat == 1)
+ {
+ int i;
+ HB_ClassDefFormat1 *ClassDefFormat1 = &ClassDefinition->cd.cd1;
+ DUMP("<ClassDefinition>\n");
+ DUMP_FUINT (ClassDefFormat1, StartGlyph );
+ DUMP_FUINT (ClassDefFormat1, GlyphCount );
+ for (i = 0; i < ClassDefFormat1->GlyphCount; i++)
+ DUMP2(" <Class>%d</Class> <!-- %#06x -->", ClassDefFormat1->ClassValueArray[i],
+ ClassDefFormat1->StartGlyph+i );
+ }
+ else if (ClassDefinition->ClassFormat == 2)
+ {
+ int i;
+ HB_ClassDefFormat2 *ClassDefFormat2 = &ClassDefinition->cd.cd2;
+ DUMP_FUINT (ClassDefFormat2, ClassRangeCount);
+
+ for (i = 0; i < ClassDefFormat2->ClassRangeCount; i++)
+ RECURSE_NUM (ClassRangeRecord, i, ClassRangeRecord, &ClassDefFormat2->ClassRangeRecord[i]);
+ }
+ else
+ fprintf(stderr, "invalid class def table!!!\n");
+}
+
+DEF_DUMP (SubstLookupRecord)
+{
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (SubstLookupRecord, SequenceIndex);
+ DUMP_FUINT (SubstLookupRecord, LookupListIndex);
+}
+
+DEF_DUMP (ChainSubClassRule)
+{
+ int i;
+
+ DUMP_USHORT_ARRAY (ChainSubClassRule, Backtrack, ChainSubClassRule->BacktrackGlyphCount);
+ DUMP_USHORT_ARRAY (ChainSubClassRule, Input, ChainSubClassRule->InputGlyphCount - 1);
+ DUMP_USHORT_ARRAY (ChainSubClassRule, Lookahead, ChainSubClassRule->LookaheadGlyphCount);
+
+ for (i = 0; i < ChainSubClassRule->SubstCount; i++)
+ RECURSE_NUM (SubstLookupRecord, i, SubstLookupRecord, &ChainSubClassRule->SubstLookupRecord[i]);
+
+ indent--;
+}
+
+DEF_DUMP (ChainSubClassSet)
+{
+ int i;
+
+ DUMP_FUINT( ChainSubClassSet, ChainSubClassRuleCount );
+ for (i = 0; i < ChainSubClassSet->ChainSubClassRuleCount; i++)
+ RECURSE_NUM (ChainSubClassRule, i, ChainSubClassRule, &ChainSubClassSet->ChainSubClassRule[i]);
+}
+
+static void
+Dump_GSUB_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ HB_SingleSubst *SingleSubst = &subtable->st.gsub.single;
+
+ DUMP_FUINT (SingleSubst, SubstFormat);
+ RECURSE (Coverage, Coverage, &SingleSubst->Coverage);
+
+ if (SingleSubst->SubstFormat == 1)
+ {
+ DUMP_FINT (&SingleSubst->ssf.ssf1, DeltaGlyphID);
+ }
+ else
+ {
+ int i;
+
+ DUMP_FINT (&SingleSubst->ssf.ssf2, GlyphCount);
+ for (i=0; i < SingleSubst->ssf.ssf2.GlyphCount; i++)
+ DUMP2("<Substitute>%#06x</Substitute> <!-- %d -->\n", SingleSubst->ssf.ssf2.Substitute[i], i);
+ }
+}
+
+DEF_DUMP (Ligature)
+{
+ int i;
+
+ HB_UNUSED(hb_type);
+
+ DUMP_FGLYPH (Ligature, LigGlyph);
+ DUMP_FUINT (Ligature, ComponentCount);
+
+ for (i=0; i < Ligature->ComponentCount - 1; i++)
+ DUMP1("<Component>%#06x</Component>\n", Ligature->Component[i]);
+}
+
+DEF_DUMP (LigatureSet)
+{
+ int i;
+
+ DUMP_FUINT (LigatureSet, LigatureCount);
+
+ for (i=0; i < LigatureSet->LigatureCount; i++)
+ RECURSE_NUM (Ligature, i, Ligature, &LigatureSet->Ligature[i]);
+}
+
+static void
+Dump_GSUB_Lookup_Ligature (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ int i;
+ HB_LigatureSubst *LigatureSubst = &subtable->st.gsub.ligature;
+
+ DUMP_FUINT (LigatureSubst, SubstFormat);
+ RECURSE (Coverage, Coverage, &LigatureSubst->Coverage);
+
+ DUMP_FUINT (LigatureSubst, LigatureSetCount);
+
+ for (i=0; i < LigatureSubst->LigatureSetCount; i++)
+ RECURSE_NUM (LigatureSet, i, LigatureSet, &LigatureSubst->LigatureSet[i]);
+}
+
+DEF_DUMP (ContextSubstFormat1)
+{
+ HB_UNUSED(hb_type);
+ HB_UNUSED(ContextSubstFormat1);
+
+
+ DUMP("<!-- Not implemented!!! -->\n");
+}
+
+DEF_DUMP (ContextSubstFormat2)
+{
+ DUMP_FUINT (ContextSubstFormat2, MaxContextLength);
+ RECURSE (Coverage, Coverage, &ContextSubstFormat2->Coverage);
+ RECURSE (ClassDefinition, ClassDefinition, &ContextSubstFormat2->ClassDef);
+}
+
+DEF_DUMP (ContextSubstFormat3)
+{
+ HB_UNUSED(hb_type);
+ HB_UNUSED(ContextSubstFormat3);
+
+ DUMP("<!-- Not implemented!!! -->\n");
+}
+
+static void
+Dump_GSUB_Lookup_Context (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ HB_ContextSubst *ContextSubst = &subtable->st.gsub.context;
+
+ DUMP_FUINT (ContextSubst, SubstFormat);
+ switch( ContextSubst->SubstFormat )
+ {
+ case 1:
+ Dump_ContextSubstFormat1 (&ContextSubst->csf.csf1, stream, indent+2, hb_type);
+ break;
+ case 2:
+ Dump_ContextSubstFormat2 (&ContextSubst->csf.csf2, stream, indent+2, hb_type);
+ break;
+ case 3:
+ Dump_ContextSubstFormat3 (&ContextSubst->csf.csf3, stream, indent+2, hb_type);
+ break;
+ default:
+ fprintf(stderr, "invalid subformat!!!!!\n");
+ }
+}
+
+DEF_DUMP (ChainContextSubstFormat1)
+{
+ HB_UNUSED(hb_type);
+ HB_UNUSED(ChainContextSubstFormat1);
+
+ DUMP("<!-- Not implemented!!! -->\n");
+}
+
+DEF_DUMP (ChainContextSubstFormat2)
+{
+ int i;
+
+ RECURSE (Coverage, Coverage, &ChainContextSubstFormat2->Coverage);
+ DUMP_FUINT (ChainContextSubstFormat2, MaxBacktrackLength);
+ RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->BacktrackClassDef);
+ DUMP_FUINT (ChainContextSubstFormat2, MaxInputLength);
+ RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->InputClassDef);
+ DUMP_FUINT (ChainContextSubstFormat2, MaxLookaheadLength);
+ RECURSE (ClassDefinition, ClassDefinition, &ChainContextSubstFormat2->LookaheadClassDef);
+
+ DUMP_FUINT (ChainContextSubstFormat2, ChainSubClassSetCount);
+ for (i = 0; i < ChainContextSubstFormat2->ChainSubClassSetCount; i++)
+ RECURSE (ChainSubClassSet, ChainSubClassSet, &ChainContextSubstFormat2->ChainSubClassSet[i]);
+}
+
+DEF_DUMP (ChainContextSubstFormat3)
+{
+ int i;
+
+ DUMP_FUINT (ChainContextSubstFormat3, BacktrackGlyphCount);
+ for (i = 0; i < ChainContextSubstFormat3->BacktrackGlyphCount; i++)
+ RECURSE (BacktrackCoverage, Coverage, &ChainContextSubstFormat3->BacktrackCoverage[i]);
+ DUMP_FUINT (ChainContextSubstFormat3, InputGlyphCount);
+ for (i = 0; i < ChainContextSubstFormat3->InputGlyphCount; i++)
+ RECURSE (InputCoverage, Coverage, &ChainContextSubstFormat3->InputCoverage[i]);
+ DUMP_FUINT (ChainContextSubstFormat3, LookaheadGlyphCount);
+ for (i = 0; i < ChainContextSubstFormat3->LookaheadGlyphCount; i++)
+ RECURSE (LookaheadCoverage, Coverage, &ChainContextSubstFormat3->LookaheadCoverage[i]);
+
+ for (i = 0; i < ChainContextSubstFormat3->SubstCount; i++)
+ RECURSE_NUM (SubstLookupRecord, i, SubstLookupRecord, &ChainContextSubstFormat3->SubstLookupRecord[i]);
+
+}
+
+static void
+Dump_GSUB_Lookup_Chain (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ HB_ChainContextSubst *chain = &subtable->st.gsub.chain;
+
+ DUMP_FUINT (chain, SubstFormat);
+ switch (chain->SubstFormat)
+ {
+ case 1:
+ Dump_ChainContextSubstFormat1 (&chain->ccsf.ccsf1, stream, indent+2, hb_type);
+ break;
+ case 2:
+ Dump_ChainContextSubstFormat2 (&chain->ccsf.ccsf2, stream, indent+2, hb_type);
+ break;
+ case 3:
+ Dump_ChainContextSubstFormat3 (&chain->ccsf.ccsf3, stream, indent+2, hb_type);
+ break;
+ default:
+ fprintf(stderr, "invalid subformat!!!!!\n");
+ }
+}
+
+static void
+Dump_Device (HB_Device *Device, FILE *stream, int indent, HB_Type hb_type)
+{
+ int i;
+ int bits;
+ int n_per;
+ unsigned int mask;
+
+ HB_UNUSED(hb_type);
+
+ DUMP_FUINT (Device, StartSize);
+ DUMP_FUINT (Device, EndSize);
+ DUMP_FUINT (Device, DeltaFormat);
+ switch (Device->DeltaFormat)
+ {
+ case 1:
+ bits = 2;
+ break;
+ case 2:
+ bits = 4;
+ break;
+ case 3:
+ bits = 8;
+ break;
+ default:
+ bits = 0;
+ break;
+ }
+
+ DUMP ("<DeltaValue>");
+ if (!bits)
+ {
+
+ fprintf(stderr, "invalid DeltaFormat!!!!!\n");
+ }
+ else
+ {
+ n_per = 16 / bits;
+ mask = (1 << bits) - 1;
+ mask = mask << (16 - bits);
+
+ for (i = Device->StartSize; i <= Device->EndSize ; i++)
+ {
+ HB_UShort val = Device->DeltaValue[i / n_per];
+ HB_Short signed_val = ((val << ((i % n_per) * bits)) & mask);
+ dump (stream, indent, "%d", signed_val >> (16 - bits));
+ if (i != Device->EndSize)
+ DUMP (", ");
+ }
+ }
+ DUMP ("</DeltaValue>\n");
+}
+
+static void
+Dump_ValueRecord (HB_ValueRecord *ValueRecord, FILE *stream, int indent, HB_Type hb_type, HB_UShort value_format)
+{
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT)
+ DUMP_FINT (ValueRecord, XPlacement);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT)
+ DUMP_FINT (ValueRecord, YPlacement);
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE)
+ DUMP_FINT (ValueRecord, XAdvance);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE)
+ DUMP_FINT (ValueRecord, XAdvance);
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE)
+ RECURSE (Device, Device, &ValueRecord->XPlacementDevice);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE)
+ RECURSE (Device, Device, &ValueRecord->YPlacementDevice);
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE)
+ RECURSE (Device, Device, &ValueRecord->XAdvanceDevice);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE)
+ RECURSE (Device, Device, &ValueRecord->YAdvanceDevice);
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT)
+ DUMP_FUINT (ValueRecord, XIdPlacement);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT)
+ DUMP_FUINT (ValueRecord, YIdPlacement);
+ if (value_format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE)
+ DUMP_FUINT (ValueRecord, XIdAdvance);
+ if (value_format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE)
+ DUMP_FUINT (ValueRecord, XIdAdvance);
+}
+
+static void
+Dump_GPOS_Lookup_Single (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ HB_SinglePos *SinglePos = &subtable->st.gpos.single;
+
+ DUMP_FUINT (SinglePos, PosFormat);
+ RECURSE (Coverage, Coverage, &SinglePos->Coverage);
+
+ DUMP_FUINT (SinglePos, ValueFormat);
+
+ if (SinglePos->PosFormat == 1)
+ {
+ DUMP_VALUE_RECORD (&SinglePos->spf.spf1.Value, SinglePos->ValueFormat);
+ }
+ else
+ {
+ int i;
+
+ DUMP_FUINT (&SinglePos->spf.spf2, ValueCount);
+ for (i = 0; i < SinglePos->spf.spf2.ValueCount; i++)
+ DUMP_VALUE_RECORD (&SinglePos->spf.spf2.Value[i], SinglePos->ValueFormat);
+ }
+}
+
+static void
+Dump_PairValueRecord (HB_PairValueRecord *PairValueRecord, FILE *stream, int indent, HB_Type hb_type, HB_UShort ValueFormat1, HB_UShort ValueFormat2)
+{
+ DUMP_FUINT (PairValueRecord, SecondGlyph);
+ DUMP_VALUE_RECORD (&PairValueRecord->Value1, ValueFormat1);
+ DUMP_VALUE_RECORD (&PairValueRecord->Value2, ValueFormat2);
+}
+
+static void
+Dump_PairSet (HB_PairSet *PairSet, FILE *stream, int indent, HB_Type hb_type, HB_UShort ValueFormat1, HB_UShort ValueFormat2)
+{
+ int i;
+ DUMP_FUINT (PairSet, PairValueCount);
+
+ for (i = 0; i < PairSet->PairValueCount; i++)
+ {
+ DUMP ("<PairValueRecord>\n");
+ Dump_PairValueRecord (&PairSet->PairValueRecord[i], stream, indent + 1, hb_type, ValueFormat1, ValueFormat2);
+ DUMP ("</PairValueRecord>\n");
+ }
+}
+
+static void
+Dump_GPOS_Lookup_Pair (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ HB_PairPos *PairPos = &subtable->st.gpos.pair;
+
+ DUMP_FUINT (PairPos, PosFormat);
+ RECURSE (Coverage, Coverage, &PairPos->Coverage);
+
+ DUMP_FUINT (PairPos, ValueFormat1);
+ DUMP_FUINT (PairPos, ValueFormat2);
+
+ if (PairPos->PosFormat == 1)
+ {
+ int i;
+
+ DUMP_FUINT (&PairPos->ppf.ppf1, PairSetCount);
+ for (i = 0; i < PairPos->ppf.ppf1.PairSetCount; i++)
+ {
+ DUMP ("<PairSet>\n");
+ Dump_PairSet (&PairPos->ppf.ppf1.PairSet[i], stream, indent + 1, hb_type, PairPos->ValueFormat1, PairPos->ValueFormat2);
+ DUMP ("</PairSet>\n");
+ }
+ }
+ else
+ {
+ }
+}
+
+static void
+Dump_GPOS_Lookup_Markbase (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type)
+{
+ int i;
+ HB_MarkBasePos *markbase = &subtable->st.gpos.markbase;
+
+ DUMP_FUINT (markbase, PosFormat);
+ RECURSE (Coverage, Coverage, &markbase->MarkCoverage);
+ RECURSE (Coverage, Coverage, &markbase->BaseCoverage);
+ DUMP_FUINT (markbase, ClassCount);
+ RECURSE (MarkArray, MarkArray, &markbase->MarkArray);
+
+ DUMP ("<BaseArray>\n");
+ indent++;
+
+ DUMP_FUINT (&markbase->BaseArray, BaseCount);
+ for (i = 0; i < markbase->BaseArray.BaseCount; i++)
+ {
+ int j;
+ HB_BaseRecord *r = &markbase->BaseArray.BaseRecord[i];
+ DUMP1 ("<BaseRecord> <!-- %d -->\n", i);
+ for (j = 0; j < markbase->ClassCount; j++)
+ DUMP1 (" <Anchor>%d</Anchor>\n", r->BaseAnchor->PosFormat);
+ DUMP ("<BaseRecord>\n");
+ }
+
+ indent--;
+ DUMP ("</BaseArray>\n");
+}
+
+DEF_DUMP (Lookup)
+{
+ int i;
+ const char *lookup_name;
+ void (*lookup_func) (HB_SubTable *subtable, FILE *stream, int indent, HB_Type hb_type) = NULL;
+
+ if (hb_type == HB_Type_GSUB)
+ {
+ switch (Lookup->LookupType)
+ {
+ case HB_GSUB_LOOKUP_SINGLE:
+ lookup_name = "SINGLE";
+ lookup_func = Dump_GSUB_Lookup_Single;
+ break;
+ case HB_GSUB_LOOKUP_MULTIPLE:
+ lookup_name = "MULTIPLE";
+ break;
+ case HB_GSUB_LOOKUP_ALTERNATE:
+ lookup_name = "ALTERNATE";
+ break;
+ case HB_GSUB_LOOKUP_LIGATURE:
+ lookup_name = "LIGATURE";
+ lookup_func = Dump_GSUB_Lookup_Ligature;
+ break;
+ case HB_GSUB_LOOKUP_CONTEXT:
+ lookup_name = "CONTEXT";
+ lookup_func = Dump_GSUB_Lookup_Context;
+ break;
+ case HB_GSUB_LOOKUP_CHAIN:
+ lookup_name = "CHAIN";
+ lookup_func = Dump_GSUB_Lookup_Chain;
+ break;
+ default:
+ lookup_name = "(unknown)";
+ lookup_func = NULL;
+ break;
+ }
+ }
+ else
+ {
+ switch (Lookup->LookupType)
+ {
+ case HB_GPOS_LOOKUP_SINGLE:
+ lookup_name = "SINGLE";
+ lookup_func = Dump_GPOS_Lookup_Single;
+ break;
+ case HB_GPOS_LOOKUP_PAIR:
+ lookup_name = "PAIR";
+ lookup_func = Dump_GPOS_Lookup_Pair;
+ break;
+ case HB_GPOS_LOOKUP_CURSIVE:
+ lookup_name = "CURSIVE";
+ break;
+ case HB_GPOS_LOOKUP_MARKBASE:
+ lookup_name = "MARKBASE";
+ lookup_func = Dump_GPOS_Lookup_Markbase;
+ break;
+ case HB_GPOS_LOOKUP_MARKLIG:
+ lookup_name = "MARKLIG";
+ break;
+ case HB_GPOS_LOOKUP_MARKMARK:
+ lookup_name = "MARKMARK";
+ break;
+ case HB_GPOS_LOOKUP_CONTEXT:
+ lookup_name = "CONTEXT";
+ break;
+ case HB_GPOS_LOOKUP_CHAIN:
+ lookup_name = "CHAIN";
+ break;
+ default:
+ lookup_name = "(unknown)";
+ lookup_func = NULL;
+ break;
+ }
+ }
+
+ DUMP2("<LookupType>%s</LookupType> <!-- %d -->\n", lookup_name, Lookup->LookupType);
+ DUMP1("<LookupFlag>%#06x</LookupFlag>\n", Lookup->LookupFlag);
+
+ for (i=0; i < Lookup->SubTableCount; i++)
+ {
+ DUMP ("<Subtable>\n");
+ if (lookup_func)
+ (*lookup_func) (&Lookup->SubTable[i], stream, indent + 1, hb_type);
+ DUMP ("</Subtable>\n");
+ }
+}
+
+DEF_DUMP (LookupList)
+{
+ int i;
+
+ DUMP_FUINT (LookupList, LookupCount);
+
+ for (i=0; i < LookupList->LookupCount; i++)
+ RECURSE_NUM (Lookup, i, Lookup, &LookupList->Lookup[i]);
+}
+
+void
+HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream)
+{
+ int indent = 1;
+ HB_Type hb_type = HB_Type_GSUB;
+
+ do_indent (stream, indent);
+ fprintf(stream, "<!-- GSUB -->\n");
+ RECURSE (ScriptList, ScriptList, &gsub->ScriptList);
+ RECURSE (FeatureList, FeatureList, &gsub->FeatureList);
+ RECURSE (LookupList, LookupList, &gsub->LookupList);
+}
+
+void
+HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream)
+{
+ int indent = 1;
+ HB_Type hb_type = HB_Type_GPOS;
+
+ do_indent (stream, indent);
+ fprintf(stream, "<!-- GPOS -->\n");
+ RECURSE (ScriptList, ScriptList, &gpos->ScriptList);
+ RECURSE (FeatureList, FeatureList, &gpos->FeatureList);
+ RECURSE (LookupList, LookupList, &gpos->LookupList);
+}
diff --git a/third_party/harfbuzz/src/harfbuzz-dump.h b/third_party/harfbuzz/src/harfbuzz-dump.h
new file mode 100644
index 0000000..ea4a62b
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-dump.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2000, 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HARFBUZZ_DUMP_H
+#define HARFBUZZ_DUMP_H
+
+#include <stdio.h>
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-gpos.h"
+
+HB_BEGIN_HEADER
+
+void HB_Dump_GSUB_Table (HB_GSUB gsub, FILE *stream);
+void HB_Dump_GPOS_Table (HB_GPOS gpos, FILE *stream);
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_DUMP_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-external.h b/third_party/harfbuzz/src/harfbuzz-external.h
new file mode 100644
index 0000000..760749b
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-external.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_EXTERNAL_H
+#define HARFBUZZ_EXTERNAL_H
+
+#include "harfbuzz-global.h"
+
+HB_BEGIN_HEADER
+
+/* This header contains some methods that are not part of
+ Harfbuzz itself, but referenced by it.
+ They need to be provided by the application/library
+*/
+
+
+/*
+ see http://www.unicode.org/reports/tr14/tr14-19.html
+ we don't use the XX, AI and CB properties and map them to AL instead.
+ as we don't support any EBDIC based OS'es, NL is ignored and mapped to AL as well.
+*/
+typedef enum {
+ HB_LineBreak_OP, HB_LineBreak_CL, HB_LineBreak_QU, HB_LineBreak_GL, HB_LineBreak_NS,
+ HB_LineBreak_EX, HB_LineBreak_SY, HB_LineBreak_IS, HB_LineBreak_PR, HB_LineBreak_PO,
+ HB_LineBreak_NU, HB_LineBreak_AL, HB_LineBreak_ID, HB_LineBreak_IN, HB_LineBreak_HY,
+ HB_LineBreak_BA, HB_LineBreak_BB, HB_LineBreak_B2, HB_LineBreak_ZW, HB_LineBreak_CM,
+ HB_LineBreak_WJ, HB_LineBreak_H2, HB_LineBreak_H3, HB_LineBreak_JL, HB_LineBreak_JV,
+ HB_LineBreak_JT, HB_LineBreak_SA, HB_LineBreak_SG,
+ HB_LineBreak_SP, HB_LineBreak_CR, HB_LineBreak_LF, HB_LineBreak_BK
+} HB_LineBreakClass;
+
+typedef enum
+{
+ HB_NoCategory,
+
+ HB_Mark_NonSpacing, /* Mn */
+ HB_Mark_SpacingCombining, /* Mc */
+ HB_Mark_Enclosing, /* Me */
+
+ HB_Number_DecimalDigit, /* Nd */
+ HB_Number_Letter, /* Nl */
+ HB_Number_Other, /* No */
+
+ HB_Separator_Space, /* Zs */
+ HB_Separator_Line, /* Zl */
+ HB_Separator_Paragraph, /* Zp */
+
+ HB_Other_Control, /* Cc */
+ HB_Other_Format, /* Cf */
+ HB_Other_Surrogate, /* Cs */
+ HB_Other_PrivateUse, /* Co */
+ HB_Other_NotAssigned, /* Cn */
+
+ HB_Letter_Uppercase, /* Lu */
+ HB_Letter_Lowercase, /* Ll */
+ HB_Letter_Titlecase, /* Lt */
+ HB_Letter_Modifier, /* Lm */
+ HB_Letter_Other, /* Lo */
+
+ HB_Punctuation_Connector, /* Pc */
+ HB_Punctuation_Dash, /* Pd */
+ HB_Punctuation_Open, /* Ps */
+ HB_Punctuation_Close, /* Pe */
+ HB_Punctuation_InitialQuote, /* Pi */
+ HB_Punctuation_FinalQuote, /* Pf */
+ HB_Punctuation_Other, /* Po */
+
+ HB_Symbol_Math, /* Sm */
+ HB_Symbol_Currency, /* Sc */
+ HB_Symbol_Modifier, /* Sk */
+ HB_Symbol_Other /* So */
+} HB_CharCategory;
+
+typedef enum
+{
+ HB_Grapheme_Other,
+ HB_Grapheme_CR,
+ HB_Grapheme_LF,
+ HB_Grapheme_Control,
+ HB_Grapheme_Extend,
+ HB_Grapheme_L,
+ HB_Grapheme_V,
+ HB_Grapheme_T,
+ HB_Grapheme_LV,
+ HB_Grapheme_LVT
+} HB_GraphemeClass;
+
+
+typedef enum
+{
+ HB_Word_Other,
+ HB_Word_Format,
+ HB_Word_Katakana,
+ HB_Word_ALetter,
+ HB_Word_MidLetter,
+ HB_Word_MidNum,
+ HB_Word_Numeric,
+ HB_Word_ExtendNumLet
+} HB_WordClass;
+
+
+typedef enum
+{
+ HB_Sentence_Other,
+ HB_Sentence_Sep,
+ HB_Sentence_Format,
+ HB_Sentence_Sp,
+ HB_Sentence_Lower,
+ HB_Sentence_Upper,
+ HB_Sentence_OLetter,
+ HB_Sentence_Numeric,
+ HB_Sentence_ATerm,
+ HB_Sentence_STerm,
+ HB_Sentence_Close
+} HB_SentenceClass;
+
+HB_GraphemeClass HB_GetGraphemeClass(HB_UChar32 ch);
+HB_WordClass HB_GetWordClass(HB_UChar32 ch);
+HB_SentenceClass HB_GetSentenceClass(HB_UChar32 ch);
+HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch);
+
+void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme, HB_LineBreakClass *lineBreak);
+void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass);
+HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch);
+int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch);
+HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch);
+
+void *HB_Library_Resolve(const char *library, const char *symbol);
+
+void *HB_TextCodecForMib(int mib);
+char *HB_TextCodec_ConvertFromUnicode(void *codec, const HB_UChar16 *unicode, hb_uint32 length, hb_uint32 *outputLength);
+void HB_TextCodec_FreeResult(char *);
+
+HB_END_HEADER
+
+#endif
diff --git a/third_party/harfbuzz/src/harfbuzz-gdef-private.h b/third_party/harfbuzz/src/harfbuzz-gdef-private.h
new file mode 100644
index 0000000..da06b6f
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gdef-private.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GDEF_PRIVATE_H
+#define HARFBUZZ_GDEF_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-stream-private.h"
+#include "harfbuzz-buffer-private.h"
+#include "harfbuzz-gdef.h"
+
+HB_BEGIN_HEADER
+
+
+/* Attachment related structures */
+
+struct HB_AttachPoint_
+{
+ HB_UShort PointCount; /* size of the PointIndex array */
+ HB_UShort* PointIndex; /* array of contour points */
+};
+
+/* Ligature Caret related structures */
+
+struct HB_CaretValueFormat1_
+{
+ HB_Short Coordinate; /* x or y value (in design units) */
+};
+
+typedef struct HB_CaretValueFormat1_ HB_CaretValueFormat1;
+
+
+struct HB_CaretValueFormat2_
+{
+ HB_UShort CaretValuePoint; /* contour point index on glyph */
+};
+
+typedef struct HB_CaretValueFormat2_ HB_CaretValueFormat2;
+
+
+struct HB_CaretValueFormat3_
+{
+ HB_Short Coordinate; /* x or y value (in design units) */
+ HB_Device Device; /* Device table for x or y value */
+};
+
+typedef struct HB_CaretValueFormat3_ HB_CaretValueFormat3;
+
+
+struct HB_CaretValueFormat4_
+{
+ HB_UShort IdCaretValue; /* metric ID */
+};
+
+typedef struct HB_CaretValueFormat4_ HB_CaretValueFormat4;
+
+
+struct HB_CaretValue_
+{
+ HB_UShort CaretValueFormat; /* 1, 2, 3, or 4 */
+
+ union
+ {
+ HB_CaretValueFormat1 cvf1;
+ HB_CaretValueFormat2 cvf2;
+ HB_CaretValueFormat3 cvf3;
+ HB_CaretValueFormat4 cvf4;
+ } cvf;
+};
+
+typedef struct HB_CaretValue_ HB_CaretValue;
+
+
+struct HB_LigGlyph_
+{
+ HB_Bool loaded;
+
+ HB_UShort CaretCount; /* number of caret values */
+ HB_CaretValue* CaretValue; /* array of caret values */
+};
+
+
+HB_INTERNAL HB_Error
+_HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
+ HB_UShort glyphID,
+ HB_UShort property );
+
+HB_INTERNAL HB_Error
+_HB_GDEF_Check_Property( HB_GDEFHeader* gdef,
+ HB_GlyphItem item,
+ HB_UShort flags,
+ HB_UShort* property );
+
+HB_INTERNAL HB_Error
+_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef,
+ HB_Stream input,
+ HB_Lookup* lo,
+ HB_UShort num_lookups );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GDEF_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-gdef.c b/third_party/harfbuzz/src/harfbuzz-gdef.c
new file mode 100644
index 0000000..ff3a1f4
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gdef.c
@@ -0,0 +1,1159 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gdef-private.h"
+#include "harfbuzz-open-private.h"
+
+static HB_Error Load_AttachList( HB_AttachList* al,
+ HB_Stream stream );
+static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
+ HB_Stream stream );
+
+static void Free_AttachList( HB_AttachList* al);
+static void Free_LigCaretList( HB_LigCaretList* lcl);
+
+static void Free_NewGlyphClasses( HB_GDEFHeader* gdef);
+
+
+
+/* GDEF glyph classes */
+
+#define UNCLASSIFIED_GLYPH 0
+#define SIMPLE_GLYPH 1
+#define LIGATURE_GLYPH 2
+#define MARK_GLYPH 3
+#define COMPONENT_GLYPH 4
+
+
+
+
+
+
+HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr )
+{
+ HB_Error error;
+
+ HB_GDEFHeader* gdef;
+
+ if ( !retptr )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( ALLOC( gdef, sizeof( *gdef ) ) )
+ return error;
+
+ gdef->GlyphClassDef.loaded = FALSE;
+ gdef->AttachList.loaded = FALSE;
+ gdef->LigCaretList.loaded = FALSE;
+ gdef->MarkAttachClassDef_offset = 0;
+ gdef->MarkAttachClassDef.loaded = FALSE;
+
+ gdef->LastGlyph = 0;
+ gdef->NewGlyphClasses = NULL;
+
+ *retptr = gdef;
+
+ return HB_Err_Ok;
+}
+
+
+HB_Error HB_Load_GDEF_Table( HB_Stream stream,
+ HB_GDEFHeader** retptr )
+{
+ HB_Error error;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_GDEFHeader* gdef;
+
+
+ if ( !retptr )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( GOTO_Table( TTAG_GDEF ) )
+ return error;
+
+ if (( error = HB_New_GDEF_Table ( &gdef ) ))
+ return error;
+
+ base_offset = FILE_Pos();
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ goto Fail0;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ /* all GDEF subtables are optional */
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ /* only classes 1-4 are allowed here */
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &gdef->GlyphClassDef, 5,
+ stream ) ) != HB_Err_Ok )
+ goto Fail0;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_AttachList( &gdef->AttachList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LigCaretList( &gdef->LigCaretList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ /* OpenType 1.2 has introduced the `MarkAttachClassDef' field. We
+ first have to scan the LookupFlag values to find out whether we
+ must load it or not. Here we only store the offset of the table. */
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ gdef->MarkAttachClassDef_offset = new_offset + base_offset;
+ else
+ gdef->MarkAttachClassDef_offset = 0;
+
+ *retptr = gdef;
+
+ return HB_Err_Ok;
+
+Fail3:
+ Free_LigCaretList( &gdef->LigCaretList );
+
+Fail2:
+ Free_AttachList( &gdef->AttachList );
+
+Fail1:
+ _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
+
+Fail0:
+ FREE( gdef );
+
+ return error;
+}
+
+
+HB_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef )
+{
+ Free_LigCaretList( &gdef->LigCaretList );
+ Free_AttachList( &gdef->AttachList );
+ _HB_OPEN_Free_ClassDefinition( &gdef->GlyphClassDef );
+ _HB_OPEN_Free_ClassDefinition( &gdef->MarkAttachClassDef );
+
+ Free_NewGlyphClasses( gdef );
+
+ FREE( gdef );
+
+ return HB_Err_Ok;
+}
+
+
+
+
+/*******************************
+ * AttachList related functions
+ *******************************/
+
+
+/* AttachPoint */
+
+static HB_Error Load_AttachPoint( HB_AttachPoint* ap,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* pi;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ap->PointCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ap->PointIndex = NULL;
+
+ if ( count )
+ {
+ if ( ALLOC_ARRAY( ap->PointIndex, count, HB_UShort ) )
+ return error;
+
+ pi = ap->PointIndex;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( pi );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ pi[n] = GET_UShort();
+
+ FORGET_Frame();
+ }
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_AttachPoint( HB_AttachPoint* ap )
+{
+ FREE( ap->PointIndex );
+}
+
+
+/* AttachList */
+
+static HB_Error Load_AttachList( HB_AttachList* al,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_AttachPoint* ap;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &al->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = al->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ al->AttachPoint = NULL;
+
+ if ( ALLOC_ARRAY( al->AttachPoint, count, HB_AttachPoint ) )
+ goto Fail2;
+
+ ap = al->AttachPoint;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_AttachPoint( &ap[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ al->loaded = TRUE;
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_AttachPoint( &ap[m] );
+
+ FREE( ap );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &al->Coverage );
+ return error;
+}
+
+
+static void Free_AttachList( HB_AttachList* al)
+{
+ HB_UShort n, count;
+
+ HB_AttachPoint* ap;
+
+
+ if ( !al->loaded )
+ return;
+
+ if ( al->AttachPoint )
+ {
+ count = al->GlyphCount;
+ ap = al->AttachPoint;
+
+ for ( n = 0; n < count; n++ )
+ Free_AttachPoint( &ap[n] );
+
+ FREE( ap );
+ }
+
+ _HB_OPEN_Free_Coverage( &al->Coverage );
+}
+
+
+
+/*********************************
+ * LigCaretList related functions
+ *********************************/
+
+
+/* CaretValueFormat1 */
+/* CaretValueFormat2 */
+/* CaretValueFormat3 */
+/* CaretValueFormat4 */
+
+static HB_Error Load_CaretValue( HB_CaretValue* cv,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cv->CaretValueFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cv->CaretValueFormat )
+ {
+ case 1:
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cv->cvf.cvf1.Coordinate = GET_Short();
+
+ FORGET_Frame();
+
+ break;
+
+ case 2:
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cv->cvf.cvf2.CaretValuePoint = GET_UShort();
+
+ FORGET_Frame();
+
+ break;
+
+ case 3:
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ cv->cvf.cvf3.Coordinate = GET_Short();
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &cv->cvf.cvf3.Device,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ break;
+
+ case 4:
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cv->cvf.cvf4.IdCaretValue = GET_UShort();
+
+ FORGET_Frame();
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_CaretValue( HB_CaretValue* cv)
+{
+ if ( cv->CaretValueFormat == 3 )
+ _HB_OPEN_Free_Device( &cv->cvf.cvf3.Device );
+}
+
+
+/* LigGlyph */
+
+static HB_Error Load_LigGlyph( HB_LigGlyph* lg,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_CaretValue* cv;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = lg->CaretCount = GET_UShort();
+
+ FORGET_Frame();
+
+ lg->CaretValue = NULL;
+
+ if ( ALLOC_ARRAY( lg->CaretValue, count, HB_CaretValue ) )
+ return error;
+
+ cv = lg->CaretValue;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_CaretValue( &cv[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_CaretValue( &cv[m] );
+
+ FREE( cv );
+ return error;
+}
+
+
+static void Free_LigGlyph( HB_LigGlyph* lg)
+{
+ HB_UShort n, count;
+
+ HB_CaretValue* cv;
+
+
+ if ( lg->CaretValue )
+ {
+ count = lg->CaretCount;
+ cv = lg->CaretValue;
+
+ for ( n = 0; n < count; n++ )
+ Free_CaretValue( &cv[n] );
+
+ FREE( cv );
+ }
+}
+
+
+/* LigCaretList */
+
+static HB_Error Load_LigCaretList( HB_LigCaretList* lcl,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort m, n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LigGlyph* lg;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &lcl->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = lcl->LigGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ lcl->LigGlyph = NULL;
+
+ if ( ALLOC_ARRAY( lcl->LigGlyph, count, HB_LigGlyph ) )
+ goto Fail2;
+
+ lg = lcl->LigGlyph;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LigGlyph( &lg[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ lcl->loaded = TRUE;
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_LigGlyph( &lg[m] );
+
+ FREE( lg );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &lcl->Coverage );
+ return error;
+}
+
+
+static void Free_LigCaretList( HB_LigCaretList* lcl )
+{
+ HB_UShort n, count;
+
+ HB_LigGlyph* lg;
+
+
+ if ( !lcl->loaded )
+ return;
+
+ if ( lcl->LigGlyph )
+ {
+ count = lcl->LigGlyphCount;
+ lg = lcl->LigGlyph;
+
+ for ( n = 0; n < count; n++ )
+ Free_LigGlyph( &lg[n] );
+
+ FREE( lg );
+ }
+
+ _HB_OPEN_Free_Coverage( &lcl->Coverage );
+}
+
+
+
+/***********
+ * GDEF API
+ ***********/
+
+
+static HB_UShort Get_New_Class( HB_GDEFHeader* gdef,
+ HB_UShort glyphID,
+ HB_UShort index )
+{
+ HB_UShort glyph_index, array_index, count;
+ HB_UShort byte, bits;
+
+ HB_ClassRangeRecord* gcrr;
+ HB_UShort** ngc;
+
+
+ if ( glyphID >= gdef->LastGlyph )
+ return 0;
+
+ count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
+ gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+ ngc = gdef->NewGlyphClasses;
+
+ if ( index < count && glyphID < gcrr[index].Start )
+ {
+ array_index = index;
+ if ( index == 0 )
+ glyph_index = glyphID;
+ else
+ glyph_index = glyphID - gcrr[index - 1].End - 1;
+ }
+ else
+ {
+ array_index = index + 1;
+ glyph_index = glyphID - gcrr[index].End - 1;
+ }
+
+ byte = ngc[array_index][glyph_index / 4];
+ bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+
+ return bits & 0x000F;
+}
+
+
+
+HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef,
+ HB_UShort glyphID,
+ HB_UShort* property )
+{
+ HB_UShort class = 0, index = 0; /* shut compiler up */
+
+ HB_Error error;
+
+
+ if ( !gdef || !property )
+ return ERR(HB_Err_Invalid_Argument);
+
+ /* first, we check for mark attach classes */
+
+ if ( gdef->MarkAttachClassDef.loaded )
+ {
+ error = _HB_OPEN_Get_Class( &gdef->MarkAttachClassDef, glyphID, &class, &index );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ if ( !error )
+ {
+ *property = class << 8;
+ return HB_Err_Ok;
+ }
+ }
+
+ error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ /* if we have a constructed class table, check whether additional
+ values have been assigned */
+
+ if ( error == HB_Err_Not_Covered && gdef->NewGlyphClasses )
+ class = Get_New_Class( gdef, glyphID, index );
+
+ switch ( class )
+ {
+ default:
+ case UNCLASSIFIED_GLYPH:
+ *property = 0;
+ break;
+
+ case SIMPLE_GLYPH:
+ *property = HB_GDEF_BASE_GLYPH;
+ break;
+
+ case LIGATURE_GLYPH:
+ *property = HB_GDEF_LIGATURE;
+ break;
+
+ case MARK_GLYPH:
+ *property = HB_GDEF_MARK;
+ break;
+
+ case COMPONENT_GLYPH:
+ *property = HB_GDEF_COMPONENT;
+ break;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+static HB_Error Make_ClassRange( HB_ClassDefinition* cd,
+ HB_UShort start,
+ HB_UShort end,
+ HB_UShort class )
+{
+ HB_Error error;
+ HB_UShort index;
+
+ HB_ClassDefFormat2* cdf2;
+ HB_ClassRangeRecord* crr;
+
+
+ cdf2 = &cd->cd.cd2;
+
+ if ( REALLOC_ARRAY( cdf2->ClassRangeRecord,
+ cdf2->ClassRangeCount + 1 ,
+ HB_ClassRangeRecord ) )
+ return error;
+
+ cdf2->ClassRangeCount++;
+
+ crr = cdf2->ClassRangeRecord;
+ index = cdf2->ClassRangeCount - 1;
+
+ crr[index].Start = start;
+ crr[index].End = end;
+ crr[index].Class = class;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef,
+ HB_UShort num_glyphs,
+ HB_UShort glyph_count,
+ HB_UShort* glyph_array,
+ HB_UShort* class_array )
+{
+ HB_UShort start, curr_glyph, curr_class;
+ HB_UShort n, m, count;
+ HB_Error error;
+
+ HB_ClassDefinition* gcd;
+ HB_ClassRangeRecord* gcrr;
+ HB_UShort** ngc;
+
+
+ if ( !gdef || !glyph_array || !class_array )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gcd = &gdef->GlyphClassDef;
+
+ /* We build a format 2 table */
+
+ gcd->ClassFormat = 2;
+
+ gcd->cd.cd2.ClassRangeCount = 0;
+ gcd->cd.cd2.ClassRangeRecord = NULL;
+
+ start = glyph_array[0];
+ curr_class = class_array[0];
+ curr_glyph = start;
+
+ if ( curr_class >= 5 )
+ {
+ error = ERR(HB_Err_Invalid_Argument);
+ goto Fail4;
+ }
+
+ glyph_count--;
+
+ for ( n = 0; n < glyph_count + 1; n++ )
+ {
+ if ( curr_glyph == glyph_array[n] && curr_class == class_array[n] )
+ {
+ if ( n == glyph_count )
+ {
+ if ( ( error = Make_ClassRange( gcd, start,
+ curr_glyph,
+ curr_class) ) != HB_Err_Ok )
+ goto Fail3;
+ }
+ else
+ {
+ if ( curr_glyph == 0xFFFF )
+ {
+ error = ERR(HB_Err_Invalid_Argument);
+ goto Fail3;
+ }
+ else
+ curr_glyph++;
+ }
+ }
+ else
+ {
+ if ( ( error = Make_ClassRange( gcd, start,
+ curr_glyph - 1,
+ curr_class) ) != HB_Err_Ok )
+ goto Fail3;
+
+ if ( curr_glyph > glyph_array[n] )
+ {
+ error = ERR(HB_Err_Invalid_Argument);
+ goto Fail3;
+ }
+
+ start = glyph_array[n];
+ curr_class = class_array[n];
+ curr_glyph = start;
+
+ if ( curr_class >= 5 )
+ {
+ error = ERR(HB_Err_Invalid_Argument);
+ goto Fail3;
+ }
+
+ if ( n == glyph_count )
+ {
+ if ( ( error = Make_ClassRange( gcd, start,
+ curr_glyph,
+ curr_class) ) != HB_Err_Ok )
+ goto Fail3;
+ }
+ else
+ {
+ if ( curr_glyph == 0xFFFF )
+ {
+ error = ERR(HB_Err_Invalid_Argument);
+ goto Fail3;
+ }
+ else
+ curr_glyph++;
+ }
+ }
+ }
+
+ /* now prepare the arrays for class values assigned during the lookup
+ process */
+
+ if ( ALLOC_ARRAY( gdef->NewGlyphClasses,
+ gcd->cd.cd2.ClassRangeCount + 1, HB_UShort* ) )
+ goto Fail3;
+
+ count = gcd->cd.cd2.ClassRangeCount;
+ gcrr = gcd->cd.cd2.ClassRangeRecord;
+ ngc = gdef->NewGlyphClasses;
+
+ /* We allocate arrays for all glyphs not covered by the class range
+ records. Each element holds four class values. */
+
+ if ( count > 0 )
+ {
+ if ( gcrr[0].Start )
+ {
+ if ( ALLOC_ARRAY( ngc[0], ( gcrr[0].Start + 3 ) / 4, HB_UShort ) )
+ goto Fail2;
+ }
+
+ for ( n = 1; n < count; n++ )
+ {
+ if ( gcrr[n].Start - gcrr[n - 1].End > 1 )
+ if ( ALLOC_ARRAY( ngc[n],
+ ( gcrr[n].Start - gcrr[n - 1].End + 2 ) / 4,
+ HB_UShort ) )
+ goto Fail1;
+ }
+
+ if ( gcrr[count - 1].End != num_glyphs - 1 )
+ {
+ if ( ALLOC_ARRAY( ngc[count],
+ ( num_glyphs - gcrr[count - 1].End + 2 ) / 4,
+ HB_UShort ) )
+ goto Fail1;
+ }
+ }
+ else if ( num_glyphs > 0 )
+ {
+ if ( ALLOC_ARRAY( ngc[count],
+ ( num_glyphs + 3 ) / 4,
+ HB_UShort ) )
+ goto Fail2;
+ }
+
+ gdef->LastGlyph = num_glyphs - 1;
+
+ gdef->MarkAttachClassDef_offset = 0L;
+ gdef->MarkAttachClassDef.loaded = FALSE;
+
+ gcd->loaded = TRUE;
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ FREE( ngc[m] );
+
+Fail2:
+ FREE( gdef->NewGlyphClasses );
+
+Fail3:
+ FREE( gcd->cd.cd2.ClassRangeRecord );
+
+Fail4:
+ return error;
+}
+
+
+static void Free_NewGlyphClasses( HB_GDEFHeader* gdef )
+{
+ HB_UShort** ngc;
+ HB_UShort n, count;
+
+
+ if ( gdef->NewGlyphClasses )
+ {
+ count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount + 1;
+ ngc = gdef->NewGlyphClasses;
+
+ for ( n = 0; n < count; n++ )
+ FREE( ngc[n] );
+
+ FREE( ngc );
+ }
+}
+
+
+HB_INTERNAL HB_Error
+_HB_GDEF_Add_Glyph_Property( HB_GDEFHeader* gdef,
+ HB_UShort glyphID,
+ HB_UShort property )
+{
+ HB_Error error;
+ HB_UShort class, new_class, index = 0; /* shut compiler up */
+ HB_UShort byte, bits, mask;
+ HB_UShort array_index, glyph_index, count;
+
+ HB_ClassRangeRecord* gcrr;
+ HB_UShort** ngc;
+
+
+ error = _HB_OPEN_Get_Class( &gdef->GlyphClassDef, glyphID, &class, &index );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ /* we don't accept glyphs covered in `GlyphClassDef' */
+
+ if ( !error )
+ return HB_Err_Not_Covered;
+
+ switch ( property )
+ {
+ case 0:
+ new_class = UNCLASSIFIED_GLYPH;
+ break;
+
+ case HB_GDEF_BASE_GLYPH:
+ new_class = SIMPLE_GLYPH;
+ break;
+
+ case HB_GDEF_LIGATURE:
+ new_class = LIGATURE_GLYPH;
+ break;
+
+ case HB_GDEF_MARK:
+ new_class = MARK_GLYPH;
+ break;
+
+ case HB_GDEF_COMPONENT:
+ new_class = COMPONENT_GLYPH;
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_Argument);
+ }
+
+ count = gdef->GlyphClassDef.cd.cd2.ClassRangeCount;
+ gcrr = gdef->GlyphClassDef.cd.cd2.ClassRangeRecord;
+ ngc = gdef->NewGlyphClasses;
+
+ if ( index < count && glyphID < gcrr[index].Start )
+ {
+ array_index = index;
+ if ( index == 0 )
+ glyph_index = glyphID;
+ else
+ glyph_index = glyphID - gcrr[index - 1].End - 1;
+ }
+ else
+ {
+ array_index = index + 1;
+ glyph_index = glyphID - gcrr[index].End - 1;
+ }
+
+ byte = ngc[array_index][glyph_index / 4];
+ bits = byte >> ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+ class = bits & 0x000F;
+
+ /* we don't overwrite existing entries */
+
+ if ( !class )
+ {
+ bits = new_class << ( 16 - ( glyph_index % 4 + 1 ) * 4 );
+ mask = ~( 0x000F << ( 16 - ( glyph_index % 4 + 1 ) * 4 ) );
+
+ ngc[array_index][glyph_index / 4] &= mask;
+ ngc[array_index][glyph_index / 4] |= bits;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_GDEF_Check_Property( HB_GDEFHeader* gdef,
+ HB_GlyphItem gitem,
+ HB_UShort flags,
+ HB_UShort* property )
+{
+ HB_Error error;
+
+ if ( gdef )
+ {
+ HB_UShort basic_glyph_class;
+ HB_UShort desired_attachment_class;
+
+ if ( gitem->gproperties == HB_GLYPH_PROPERTIES_UNKNOWN )
+ {
+ error = HB_GDEF_Get_Glyph_Property( gdef, gitem->gindex, &gitem->gproperties );
+ if ( error )
+ return error;
+ }
+
+ *property = gitem->gproperties;
+
+ /* If the glyph was found in the MarkAttachmentClass table,
+ * then that class value is the high byte of the result,
+ * otherwise the low byte contains the basic type of the glyph
+ * as defined by the GlyphClassDef table.
+ */
+ if ( *property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+ basic_glyph_class = HB_GDEF_MARK;
+ else
+ basic_glyph_class = *property;
+
+ /* Return Not_Covered, if, for example, basic_glyph_class
+ * is HB_GDEF_LIGATURE and LookFlags includes HB_LOOKUP_FLAG_IGNORE_LIGATURES
+ */
+ if ( flags & basic_glyph_class )
+ return HB_Err_Not_Covered;
+
+ /* The high byte of LookupFlags has the meaning
+ * "ignore marks of attachment type different than
+ * the attachment type specified."
+ */
+ desired_attachment_class = flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS;
+ if ( desired_attachment_class )
+ {
+ if ( basic_glyph_class == HB_GDEF_MARK &&
+ *property != desired_attachment_class )
+ return HB_Err_Not_Covered;
+ }
+ } else {
+ *property = 0;
+ }
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_Error
+_HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( HB_GDEFHeader* gdef,
+ HB_Stream stream,
+ HB_Lookup* lo,
+ HB_UShort num_lookups)
+{
+ HB_Error error = HB_Err_Ok;
+ HB_UShort i;
+
+ /* We now check the LookupFlags for values larger than 0xFF to find
+ out whether we need to load the `MarkAttachClassDef' field of the
+ GDEF table -- this hack is necessary for OpenType 1.2 tables since
+ the version field of the GDEF table hasn't been incremented.
+
+ For constructed GDEF tables, we only load it if
+ `MarkAttachClassDef_offset' is not zero (nevertheless, a build of
+ a constructed mark attach table is not supported currently). */
+
+ if ( gdef &&
+ gdef->MarkAttachClassDef_offset && !gdef->MarkAttachClassDef.loaded )
+ {
+ for ( i = 0; i < num_lookups; i++ )
+ {
+
+ if ( lo[i].LookupFlag & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+ {
+ if ( FILE_Seek( gdef->MarkAttachClassDef_offset ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &gdef->MarkAttachClassDef,
+ 256, stream ) ) != HB_Err_Ok )
+ goto Done;
+
+ break;
+ }
+ }
+ }
+
+Done:
+ return error;
+}
+
+/* END */
diff --git a/third_party/harfbuzz/src/harfbuzz-gdef.h b/third_party/harfbuzz/src/harfbuzz-gdef.h
new file mode 100644
index 0000000..b6dcadc
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gdef.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GDEF_H
+#define HARFBUZZ_GDEF_H
+
+#include "harfbuzz-open.h"
+#include "harfbuzz-stream.h"
+
+HB_BEGIN_HEADER
+
+/* GDEF glyph properties. Note that HB_GDEF_COMPONENT has no corresponding
+ * flag in the LookupFlag field. */
+#define HB_GDEF_BASE_GLYPH 0x0002
+#define HB_GDEF_LIGATURE 0x0004
+#define HB_GDEF_MARK 0x0008
+#define HB_GDEF_COMPONENT 0x0010
+
+
+typedef struct HB_AttachPoint_ HB_AttachPoint;
+
+
+struct HB_AttachList_
+{
+ HB_Bool loaded;
+
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort GlyphCount; /* number of glyphs with
+ attachments */
+ HB_AttachPoint* AttachPoint; /* array of AttachPoint tables */
+};
+
+typedef struct HB_AttachList_ HB_AttachList;
+
+typedef struct HB_LigGlyph_ HB_LigGlyph;
+
+struct HB_LigCaretList_
+{
+ HB_Bool loaded;
+
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort LigGlyphCount; /* number of ligature glyphs */
+ HB_LigGlyph* LigGlyph; /* array of LigGlyph tables */
+};
+
+typedef struct HB_LigCaretList_ HB_LigCaretList;
+
+
+
+/* The `NewGlyphClasses' field is not defined in the TTO specification.
+ We use it for fonts with a constructed `GlyphClassDef' structure
+ (i.e., which don't have a GDEF table) to collect glyph classes
+ assigned during the lookup process. The number of arrays in this
+ pointer array is GlyphClassDef->cd.cd2.ClassRangeCount+1; the nth
+ array then contains the glyph class values of the glyphs not covered
+ by the ClassRangeRecords structures with index n-1 and n. We store
+ glyph class values for four glyphs in a single array element.
+
+ `LastGlyph' is identical to the number of glyphs minus one in the
+ font; we need it only if `NewGlyphClasses' is not NULL (to have an
+ upper bound for the last array).
+
+ Note that we first store the file offset to the `MarkAttachClassDef'
+ field (which has been introduced in OpenType 1.2) -- since the
+ `Version' field value hasn't been increased to indicate that we have
+ one more field for some obscure reason, we must parse the GSUB table
+ to find out whether class values refer to this table. Only then we
+ can finally load the MarkAttachClassDef structure if necessary. */
+
+struct HB_GDEFHeader_
+{
+ HB_UInt offset;
+
+ HB_16Dot16 Version;
+
+ HB_ClassDefinition GlyphClassDef;
+ HB_AttachList AttachList;
+ HB_LigCaretList LigCaretList;
+ HB_UInt MarkAttachClassDef_offset;
+ HB_ClassDefinition MarkAttachClassDef; /* new in OT 1.2 */
+
+ HB_UShort LastGlyph;
+ HB_UShort** NewGlyphClasses;
+};
+
+typedef struct HB_GDEFHeader_ HB_GDEFHeader;
+typedef struct HB_GDEFHeader_* HB_GDEF;
+
+
+HB_Error HB_New_GDEF_Table( HB_GDEFHeader** retptr );
+
+
+HB_Error HB_Load_GDEF_Table( HB_Stream stream,
+ HB_GDEFHeader** gdef );
+
+
+HB_Error HB_Done_GDEF_Table ( HB_GDEFHeader* gdef );
+
+
+HB_Error HB_GDEF_Get_Glyph_Property( HB_GDEFHeader* gdef,
+ HB_UShort glyphID,
+ HB_UShort* property );
+
+HB_Error HB_GDEF_Build_ClassDefinition( HB_GDEFHeader* gdef,
+ HB_UShort num_glyphs,
+ HB_UShort glyph_count,
+ HB_UShort* glyph_array,
+ HB_UShort* class_array );
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GDEF_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-global.h b/third_party/harfbuzz/src/harfbuzz-global.h
new file mode 100644
index 0000000..d4e6b46
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-global.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HARFBUZZ_GLOBAL_H
+#define HARFBUZZ_GLOBAL_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+#define HB_BEGIN_HEADER extern "C" {
+#define HB_END_HEADER }
+#else
+#define HB_BEGIN_HEADER /* nothing */
+#define HB_END_HEADER /* nothing */
+#endif
+
+HB_BEGIN_HEADER
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#define HB_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
+ ( ( (HB_UInt)_x1 << 24 ) | \
+ ( (HB_UInt)_x2 << 16 ) | \
+ ( (HB_UInt)_x3 << 8 ) | \
+ (HB_UInt)_x4 )
+
+typedef char hb_int8;
+typedef unsigned char hb_uint8;
+typedef short hb_int16;
+typedef unsigned short hb_uint16;
+typedef int hb_int32;
+typedef unsigned int hb_uint32;
+
+typedef hb_uint8 HB_Bool;
+
+typedef hb_uint8 HB_Byte;
+typedef hb_uint16 HB_UShort;
+typedef hb_uint32 HB_UInt;
+typedef hb_int8 HB_Char;
+typedef hb_int16 HB_Short;
+typedef hb_int32 HB_Int;
+
+typedef hb_uint16 HB_UChar16;
+typedef hb_uint32 HB_UChar32;
+typedef hb_uint32 HB_Glyph;
+typedef hb_int32 HB_Fixed; /* 26.6 */
+
+#define HB_FIXED_CONSTANT(v) ((v) * 64)
+#define HB_FIXED_ROUND(v) (((v)+32) & -64)
+
+typedef hb_int32 HB_16Dot16; /* 16.16 */
+
+typedef void * HB_Pointer;
+typedef hb_uint32 HB_Tag;
+
+typedef enum {
+ /* no error */
+ HB_Err_Ok = 0x0000,
+ HB_Err_Not_Covered = 0xFFFF,
+
+ /* _hb_err() is called whenever returning the following errors,
+ * and in a couple places for HB_Err_Not_Covered too. */
+
+ /* programmer error */
+ HB_Err_Invalid_Argument = 0x1A66,
+
+ /* font error */
+ HB_Err_Invalid_SubTable_Format = 0x157F,
+ HB_Err_Invalid_SubTable = 0x1570,
+ HB_Err_Read_Error = 0x6EAD,
+
+ /* system error */
+ HB_Err_Out_Of_Memory = 0xDEAD
+} HB_Error;
+
+typedef struct {
+ HB_Fixed x;
+ HB_Fixed y;
+} HB_FixedPoint;
+
+typedef struct HB_Font_ *HB_Font;
+typedef struct HB_StreamRec_ *HB_Stream;
+typedef struct HB_FaceRec_ *HB_Face;
+
+HB_END_HEADER
+
+#endif
diff --git a/third_party/harfbuzz/src/harfbuzz-gpos-private.h b/third_party/harfbuzz/src/harfbuzz-gpos-private.h
new file mode 100644
index 0000000..411070084
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gpos-private.h
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GPOS_PRIVATE_H
+#define HARFBUZZ_GPOS_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-stream-private.h"
+#include "harfbuzz-gpos.h"
+
+HB_BEGIN_HEADER
+
+
+/* shared tables */
+
+struct HB_ValueRecord_
+{
+ HB_Short XPlacement; /* horizontal adjustment for
+ placement */
+ HB_Short YPlacement; /* vertical adjustment for
+ placement */
+ HB_Short XAdvance; /* horizontal adjustment for
+ advance */
+ HB_Short YAdvance; /* vertical adjustment for
+ advance */
+ HB_Device XPlacementDevice; /* device table for horizontal
+ placement */
+ HB_Device YPlacementDevice; /* device table for vertical
+ placement */
+ HB_Device XAdvanceDevice; /* device table for horizontal
+ advance */
+ HB_Device YAdvanceDevice; /* device table for vertical
+ advance */
+ HB_UShort XIdPlacement; /* horizontal placement metric ID */
+ HB_UShort YIdPlacement; /* vertical placement metric ID */
+ HB_UShort XIdAdvance; /* horizontal advance metric ID */
+ HB_UShort YIdAdvance; /* vertical advance metric ID */
+};
+
+typedef struct HB_ValueRecord_ HB_ValueRecord;
+
+
+/* Mask values to scan the value format of the ValueRecord structure.
+ We always expand compressed ValueRecords of the font. */
+
+#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT 0x0001
+#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT 0x0002
+#define HB_GPOS_FORMAT_HAVE_X_ADVANCE 0x0004
+#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE 0x0008
+#define HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE 0x0010
+#define HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE 0x0020
+#define HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE 0x0040
+#define HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE 0x0080
+#define HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT 0x0100
+#define HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT 0x0200
+#define HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE 0x0400
+#define HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE 0x0800
+
+
+struct HB_AnchorFormat1_
+{
+ HB_Short XCoordinate; /* horizontal value */
+ HB_Short YCoordinate; /* vertical value */
+};
+
+typedef struct HB_AnchorFormat1_ HB_AnchorFormat1;
+
+
+struct HB_AnchorFormat2_
+{
+ HB_Short XCoordinate; /* horizontal value */
+ HB_Short YCoordinate; /* vertical value */
+ HB_UShort AnchorPoint; /* index to glyph contour point */
+};
+
+typedef struct HB_AnchorFormat2_ HB_AnchorFormat2;
+
+
+struct HB_AnchorFormat3_
+{
+ HB_Short XCoordinate; /* horizontal value */
+ HB_Short YCoordinate; /* vertical value */
+ HB_Device XDeviceTable; /* device table for X coordinate */
+ HB_Device YDeviceTable; /* device table for Y coordinate */
+};
+
+typedef struct HB_AnchorFormat3_ HB_AnchorFormat3;
+
+
+struct HB_AnchorFormat4_
+{
+ HB_UShort XIdAnchor; /* horizontal metric ID */
+ HB_UShort YIdAnchor; /* vertical metric ID */
+};
+
+typedef struct HB_AnchorFormat4_ HB_AnchorFormat4;
+
+
+struct HB_Anchor_
+{
+ HB_UShort PosFormat; /* 1, 2, 3, or 4 -- 0 indicates
+ that there is no Anchor table */
+
+ union
+ {
+ HB_AnchorFormat1 af1;
+ HB_AnchorFormat2 af2;
+ HB_AnchorFormat3 af3;
+ HB_AnchorFormat4 af4;
+ } af;
+};
+
+typedef struct HB_Anchor_ HB_Anchor;
+
+
+struct HB_MarkRecord_
+{
+ HB_UShort Class; /* mark class */
+ HB_Anchor MarkAnchor; /* anchor table */
+};
+
+typedef struct HB_MarkRecord_ HB_MarkRecord;
+
+
+struct HB_MarkArray_
+{
+ HB_UShort MarkCount; /* number of MarkRecord tables */
+ HB_MarkRecord* MarkRecord; /* array of MarkRecord tables */
+};
+
+typedef struct HB_MarkArray_ HB_MarkArray;
+
+
+/* LookupType 1 */
+
+struct HB_SinglePosFormat1_
+{
+ HB_ValueRecord Value; /* ValueRecord for all covered
+ glyphs */
+};
+
+typedef struct HB_SinglePosFormat1_ HB_SinglePosFormat1;
+
+
+struct HB_SinglePosFormat2_
+{
+ HB_UShort ValueCount; /* number of ValueRecord tables */
+ HB_ValueRecord* Value; /* array of ValueRecord tables */
+};
+
+typedef struct HB_SinglePosFormat2_ HB_SinglePosFormat2;
+
+
+struct HB_SinglePos_
+{
+ HB_UShort PosFormat; /* 1 or 2 */
+ HB_Coverage Coverage; /* Coverage table */
+
+ HB_UShort ValueFormat; /* format of ValueRecord table */
+
+ union
+ {
+ HB_SinglePosFormat1 spf1;
+ HB_SinglePosFormat2 spf2;
+ } spf;
+};
+
+typedef struct HB_SinglePos_ HB_SinglePos;
+
+
+/* LookupType 2 */
+
+struct HB_PairValueRecord_
+{
+ HB_UShort SecondGlyph; /* glyph ID for second glyph */
+ HB_ValueRecord Value1; /* pos. data for first glyph */
+ HB_ValueRecord Value2; /* pos. data for second glyph */
+};
+
+typedef struct HB_PairValueRecord_ HB_PairValueRecord;
+
+
+struct HB_PairSet_
+{
+ HB_UShort PairValueCount;
+ /* number of PairValueRecord tables */
+ HB_PairValueRecord* PairValueRecord;
+ /* array of PairValueRecord tables */
+};
+
+typedef struct HB_PairSet_ HB_PairSet;
+
+
+struct HB_PairPosFormat1_
+{
+ HB_UShort PairSetCount; /* number of PairSet tables */
+ HB_PairSet* PairSet; /* array of PairSet tables */
+};
+
+typedef struct HB_PairPosFormat1_ HB_PairPosFormat1;
+
+
+struct HB_Class2Record_
+{
+ HB_ValueRecord Value1; /* pos. data for first glyph */
+ HB_ValueRecord Value2; /* pos. data for second glyph */
+};
+
+typedef struct HB_Class2Record_ HB_Class2Record;
+
+
+struct HB_Class1Record_
+{
+ HB_Class2Record* Class2Record; /* array of Class2Record tables */
+};
+
+typedef struct HB_Class1Record_ HB_Class1Record;
+
+
+struct HB_PairPosFormat2_
+{
+ HB_ClassDefinition ClassDef1; /* class def. for first glyph */
+ HB_ClassDefinition ClassDef2; /* class def. for second glyph */
+ HB_UShort Class1Count; /* number of classes in ClassDef1
+ table */
+ HB_UShort Class2Count; /* number of classes in ClassDef2
+ table */
+ HB_Class1Record* Class1Record; /* array of Class1Record tables */
+};
+
+typedef struct HB_PairPosFormat2_ HB_PairPosFormat2;
+
+
+struct HB_PairPos_
+{
+ HB_UShort PosFormat; /* 1 or 2 */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort ValueFormat1; /* format of ValueRecord table
+ for first glyph */
+ HB_UShort ValueFormat2; /* format of ValueRecord table
+ for second glyph */
+
+ union
+ {
+ HB_PairPosFormat1 ppf1;
+ HB_PairPosFormat2 ppf2;
+ } ppf;
+};
+
+typedef struct HB_PairPos_ HB_PairPos;
+
+
+/* LookupType 3 */
+
+struct HB_EntryExitRecord_
+{
+ HB_Anchor EntryAnchor; /* entry Anchor table */
+ HB_Anchor ExitAnchor; /* exit Anchor table */
+};
+
+
+typedef struct HB_EntryExitRecord_ HB_EntryExitRecord;
+
+struct HB_CursivePos_
+{
+ HB_UShort PosFormat; /* always 1 */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort EntryExitCount;
+ /* number of EntryExitRecord tables */
+ HB_EntryExitRecord* EntryExitRecord;
+ /* array of EntryExitRecord tables */
+};
+
+typedef struct HB_CursivePos_ HB_CursivePos;
+
+
+/* LookupType 4 */
+
+struct HB_BaseRecord_
+{
+ HB_Anchor* BaseAnchor; /* array of base glyph anchor
+ tables */
+};
+
+typedef struct HB_BaseRecord_ HB_BaseRecord;
+
+
+struct HB_BaseArray_
+{
+ HB_UShort BaseCount; /* number of BaseRecord tables */
+ HB_BaseRecord* BaseRecord; /* array of BaseRecord tables */
+};
+
+typedef struct HB_BaseArray_ HB_BaseArray;
+
+
+struct HB_MarkBasePos_
+{
+ HB_UShort PosFormat; /* always 1 */
+ HB_Coverage MarkCoverage; /* mark glyph coverage table */
+ HB_Coverage BaseCoverage; /* base glyph coverage table */
+ HB_UShort ClassCount; /* number of mark classes */
+ HB_MarkArray MarkArray; /* mark array table */
+ HB_BaseArray BaseArray; /* base array table */
+};
+
+typedef struct HB_MarkBasePos_ HB_MarkBasePos;
+
+
+/* LookupType 5 */
+
+struct HB_ComponentRecord_
+{
+ HB_Anchor* LigatureAnchor; /* array of ligature glyph anchor
+ tables */
+};
+
+typedef struct HB_ComponentRecord_ HB_ComponentRecord;
+
+
+struct HB_LigatureAttach_
+{
+ HB_UShort ComponentCount;
+ /* number of ComponentRecord tables */
+ HB_ComponentRecord* ComponentRecord;
+ /* array of ComponentRecord tables */
+};
+
+typedef struct HB_LigatureAttach_ HB_LigatureAttach;
+
+
+struct HB_LigatureArray_
+{
+ HB_UShort LigatureCount; /* number of LigatureAttach tables */
+ HB_LigatureAttach* LigatureAttach;
+ /* array of LigatureAttach tables */
+};
+
+typedef struct HB_LigatureArray_ HB_LigatureArray;
+
+
+struct HB_MarkLigPos_
+{
+ HB_UShort PosFormat; /* always 1 */
+ HB_Coverage MarkCoverage; /* mark glyph coverage table */
+ HB_Coverage LigatureCoverage;
+ /* ligature glyph coverage table */
+ HB_UShort ClassCount; /* number of mark classes */
+ HB_MarkArray MarkArray; /* mark array table */
+ HB_LigatureArray LigatureArray; /* ligature array table */
+};
+
+typedef struct HB_MarkLigPos_ HB_MarkLigPos;
+
+
+/* LookupType 6 */
+
+struct HB_Mark2Record_
+{
+ HB_Anchor* Mark2Anchor; /* array of mark glyph anchor
+ tables */
+};
+
+typedef struct HB_Mark2Record_ HB_Mark2Record;
+
+
+struct HB_Mark2Array_
+{
+ HB_UShort Mark2Count; /* number of Mark2Record tables */
+ HB_Mark2Record* Mark2Record; /* array of Mark2Record tables */
+};
+
+typedef struct HB_Mark2Array_ HB_Mark2Array;
+
+
+struct HB_MarkMarkPos_
+{
+ HB_UShort PosFormat; /* always 1 */
+ HB_Coverage Mark1Coverage; /* first mark glyph coverage table */
+ HB_Coverage Mark2Coverage; /* second mark glyph coverave table */
+ HB_UShort ClassCount; /* number of combining mark classes */
+ HB_MarkArray Mark1Array; /* MarkArray table for first mark */
+ HB_Mark2Array Mark2Array; /* MarkArray table for second mark */
+};
+
+typedef struct HB_MarkMarkPos_ HB_MarkMarkPos;
+
+
+/* needed by both lookup type 7 and 8 */
+
+struct HB_PosLookupRecord_
+{
+ HB_UShort SequenceIndex; /* index into current
+ glyph sequence */
+ HB_UShort LookupListIndex; /* Lookup to apply to that pos. */
+};
+
+typedef struct HB_PosLookupRecord_ HB_PosLookupRecord;
+
+
+/* LookupType 7 */
+
+struct HB_PosRule_
+{
+ HB_UShort GlyphCount; /* total number of input glyphs */
+ HB_UShort PosCount; /* number of PosLookupRecord tables */
+ HB_UShort* Input; /* array of input glyph IDs */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecord tables */
+};
+
+typedef struct HB_PosRule_ HB_PosRule;
+
+
+struct HB_PosRuleSet_
+{
+ HB_UShort PosRuleCount; /* number of PosRule tables */
+ HB_PosRule* PosRule; /* array of PosRule tables */
+};
+
+typedef struct HB_PosRuleSet_ HB_PosRuleSet;
+
+
+struct HB_ContextPosFormat1_
+{
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort PosRuleSetCount; /* number of PosRuleSet tables */
+ HB_PosRuleSet* PosRuleSet; /* array of PosRuleSet tables */
+};
+
+typedef struct HB_ContextPosFormat1_ HB_ContextPosFormat1;
+
+
+struct HB_PosClassRule_
+{
+ HB_UShort GlyphCount; /* total number of context classes */
+ HB_UShort PosCount; /* number of PosLookupRecord tables */
+ HB_UShort* Class; /* array of classes */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecord tables */
+};
+
+typedef struct HB_PosClassRule_ HB_PosClassRule;
+
+
+struct HB_PosClassSet_
+{
+ HB_UShort PosClassRuleCount;
+ /* number of PosClassRule tables */
+ HB_PosClassRule* PosClassRule; /* array of PosClassRule tables */
+};
+
+typedef struct HB_PosClassSet_ HB_PosClassSet;
+
+
+/* The `MaxContextLength' field is not defined in the TTO specification
+ but simplifies the implementation of this format. It holds the
+ maximal context length used in the context rules. */
+
+struct HB_ContextPosFormat2_
+{
+ HB_UShort MaxContextLength;
+ /* maximal context length */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_ClassDefinition ClassDef; /* ClassDef table */
+ HB_UShort PosClassSetCount;
+ /* number of PosClassSet tables */
+ HB_PosClassSet* PosClassSet; /* array of PosClassSet tables */
+};
+
+typedef struct HB_ContextPosFormat2_ HB_ContextPosFormat2;
+
+
+struct HB_ContextPosFormat3_
+{
+ HB_UShort GlyphCount; /* number of input glyphs */
+ HB_UShort PosCount; /* number of PosLookupRecord tables */
+ HB_Coverage* Coverage; /* array of Coverage tables */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecord tables */
+};
+
+typedef struct HB_ContextPosFormat3_ HB_ContextPosFormat3;
+
+
+struct HB_ContextPos_
+{
+ HB_UShort PosFormat; /* 1, 2, or 3 */
+
+ union
+ {
+ HB_ContextPosFormat1 cpf1;
+ HB_ContextPosFormat2 cpf2;
+ HB_ContextPosFormat3 cpf3;
+ } cpf;
+};
+
+typedef struct HB_ContextPos_ HB_ContextPos;
+
+
+/* LookupType 8 */
+
+struct HB_ChainPosRule_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* total number of backtrack glyphs */
+ HB_UShort* Backtrack; /* array of backtrack glyph IDs */
+ HB_UShort InputGlyphCount;
+ /* total number of input glyphs */
+ HB_UShort* Input; /* array of input glyph IDs */
+ HB_UShort LookaheadGlyphCount;
+ /* total number of lookahead glyphs */
+ HB_UShort* Lookahead; /* array of lookahead glyph IDs */
+ HB_UShort PosCount; /* number of PosLookupRecords */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of PosLookupRecords */
+};
+
+typedef struct HB_ChainPosRule_ HB_ChainPosRule;
+
+
+struct HB_ChainPosRuleSet_
+{
+ HB_UShort ChainPosRuleCount;
+ /* number of ChainPosRule tables */
+ HB_ChainPosRule* ChainPosRule; /* array of ChainPosRule tables */
+};
+
+typedef struct HB_ChainPosRuleSet_ HB_ChainPosRuleSet;
+
+
+struct HB_ChainContextPosFormat1_
+{
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort ChainPosRuleSetCount;
+ /* number of ChainPosRuleSet tables */
+ HB_ChainPosRuleSet* ChainPosRuleSet;
+ /* array of ChainPosRuleSet tables */
+};
+
+typedef struct HB_ChainContextPosFormat1_ HB_ChainContextPosFormat1;
+
+
+struct HB_ChainPosClassRule_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* total number of backtrack
+ classes */
+ HB_UShort* Backtrack; /* array of backtrack classes */
+ HB_UShort InputGlyphCount;
+ /* total number of context classes */
+ HB_UShort* Input; /* array of context classes */
+ HB_UShort LookaheadGlyphCount;
+ /* total number of lookahead
+ classes */
+ HB_UShort* Lookahead; /* array of lookahead classes */
+ HB_UShort PosCount; /* number of PosLookupRecords */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of substitution lookups */
+};
+
+typedef struct HB_ChainPosClassRule_ HB_ChainPosClassRule;
+
+
+struct HB_ChainPosClassSet_
+{
+ HB_UShort ChainPosClassRuleCount;
+ /* number of ChainPosClassRule
+ tables */
+ HB_ChainPosClassRule* ChainPosClassRule;
+ /* array of ChainPosClassRule
+ tables */
+};
+
+typedef struct HB_ChainPosClassSet_ HB_ChainPosClassSet;
+
+
+/* The `MaxXXXLength' fields are not defined in the TTO specification
+ but simplifies the implementation of this format. It holds the
+ maximal context length used in the specific context rules. */
+
+struct HB_ChainContextPosFormat2_
+{
+ HB_Coverage Coverage; /* Coverage table */
+
+ HB_UShort MaxBacktrackLength;
+ /* maximal backtrack length */
+ HB_ClassDefinition BacktrackClassDef;
+ /* BacktrackClassDef table */
+ HB_UShort MaxInputLength;
+ /* maximal input length */
+ HB_ClassDefinition InputClassDef;
+ /* InputClassDef table */
+ HB_UShort MaxLookaheadLength;
+ /* maximal lookahead length */
+ HB_ClassDefinition LookaheadClassDef;
+ /* LookaheadClassDef table */
+
+ HB_UShort ChainPosClassSetCount;
+ /* number of ChainPosClassSet
+ tables */
+ HB_ChainPosClassSet* ChainPosClassSet;
+ /* array of ChainPosClassSet
+ tables */
+};
+
+typedef struct HB_ChainContextPosFormat2_ HB_ChainContextPosFormat2;
+
+
+struct HB_ChainContextPosFormat3_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* number of backtrack glyphs */
+ HB_Coverage* BacktrackCoverage;
+ /* array of backtrack Coverage
+ tables */
+ HB_UShort InputGlyphCount;
+ /* number of input glyphs */
+ HB_Coverage* InputCoverage;
+ /* array of input coverage
+ tables */
+ HB_UShort LookaheadGlyphCount;
+ /* number of lookahead glyphs */
+ HB_Coverage* LookaheadCoverage;
+ /* array of lookahead coverage
+ tables */
+ HB_UShort PosCount; /* number of PosLookupRecords */
+ HB_PosLookupRecord* PosLookupRecord;
+ /* array of substitution lookups */
+};
+
+typedef struct HB_ChainContextPosFormat3_ HB_ChainContextPosFormat3;
+
+
+struct HB_ChainContextPos_
+{
+ HB_UShort PosFormat; /* 1, 2, or 3 */
+
+ union
+ {
+ HB_ChainContextPosFormat1 ccpf1;
+ HB_ChainContextPosFormat2 ccpf2;
+ HB_ChainContextPosFormat3 ccpf3;
+ } ccpf;
+};
+
+typedef struct HB_ChainContextPos_ HB_ChainContextPos;
+
+
+#if 0
+/* LookupType 10 */
+struct HB_ExtensionPos_
+{
+ HB_UShort PosFormat; /* always 1 */
+ HB_UShort LookuptType; /* lookup-type of referenced subtable */
+ HB_GPOS_SubTable *subtable; /* referenced subtable */
+};
+
+typedef struct HB_ExtensionPos_ HB_ExtensionPos;
+#endif
+
+
+union HB_GPOS_SubTable_
+{
+ HB_SinglePos single;
+ HB_PairPos pair;
+ HB_CursivePos cursive;
+ HB_MarkBasePos markbase;
+ HB_MarkLigPos marklig;
+ HB_MarkMarkPos markmark;
+ HB_ContextPos context;
+ HB_ChainContextPos chain;
+};
+
+typedef union HB_GPOS_SubTable_ HB_GPOS_SubTable;
+
+
+
+HB_INTERNAL HB_Error
+_HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
+ HB_Stream stream,
+ HB_UShort lookup_type );
+
+HB_INTERNAL void
+_HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
+ HB_UShort lookup_type );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GPOS_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-gpos.c b/third_party/harfbuzz/src/harfbuzz-gpos.c
new file mode 100644
index 0000000..1ac3779
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gpos.c
@@ -0,0 +1,6053 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gpos-private.h"
+#include "harfbuzz-open-private.h"
+#include "harfbuzz-gdef-private.h"
+#include "harfbuzz-shaper.h"
+
+struct GPOS_Instance_
+{
+ HB_GPOSHeader* gpos;
+ HB_Font font;
+ HB_Bool dvi;
+ HB_UShort load_flags; /* how the glyph should be loaded */
+ HB_Bool r2l;
+
+ HB_UShort last; /* the last valid glyph -- used
+ with cursive positioning */
+ HB_Fixed anchor_x; /* the coordinates of the anchor point */
+ HB_Fixed anchor_y; /* of the last valid glyph */
+};
+
+typedef struct GPOS_Instance_ GPOS_Instance;
+
+
+static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
+ HB_UShort lookup_index,
+ HB_Buffer buffer,
+ HB_UShort context_length,
+ int nesting_level );
+
+
+
+/* the client application must replace this with something more
+ meaningful if multiple master fonts are to be supported. */
+
+static HB_Error default_mmfunc( HB_Font font,
+ HB_UShort metric_id,
+ HB_Fixed* metric_value,
+ void* data )
+{
+ HB_UNUSED(font);
+ HB_UNUSED(metric_id);
+ HB_UNUSED(metric_value);
+ HB_UNUSED(data);
+ return ERR(HB_Err_Not_Covered); /* ERR() call intended */
+}
+
+
+
+HB_Error HB_Load_GPOS_Table( HB_Stream stream,
+ HB_GPOSHeader** retptr,
+ HB_GDEFHeader* gdef,
+ HB_Stream gdefStream )
+{
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_GPOSHeader* gpos;
+
+ HB_Error error;
+
+
+ if ( !retptr )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( GOTO_Table( TTAG_GPOS ) )
+ return error;
+
+ base_offset = FILE_Pos();
+
+ if ( ALLOC ( gpos, sizeof( *gpos ) ) )
+ return error;
+
+ gpos->mmfunc = default_mmfunc;
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
+ stream, HB_Type_GPOS ) ) != HB_Err_Ok )
+ goto Fail2;
+
+ gpos->gdef = gdef; /* can be NULL */
+
+ if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
+ gpos->LookupList.Lookup,
+ gpos->LookupList.LookupCount ) ) )
+ goto Fail1;
+
+ *retptr = gpos;
+
+ return HB_Err_Ok;
+
+Fail1:
+ _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
+
+Fail2:
+ _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
+
+Fail3:
+ _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
+
+Fail4:
+ FREE( gpos );
+
+ return error;
+}
+
+
+HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
+{
+ _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
+ _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
+ _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
+
+ FREE( gpos );
+
+ return HB_Err_Ok;
+}
+
+
+/*****************************
+ * SubTable related functions
+ *****************************/
+
+/* shared tables */
+
+/* ValueRecord */
+
+/* There is a subtle difference in the specs between a `table' and a
+ `record' -- offsets for device tables in ValueRecords are taken from
+ the parent table and not the parent record. */
+
+static HB_Error Load_ValueRecord( HB_ValueRecord* vr,
+ HB_UShort format,
+ HB_UInt base_offset,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UInt cur_offset, new_offset;
+
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ vr->XPlacement = GET_Short();
+
+ FORGET_Frame();
+ }
+ else
+ vr->XPlacement = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ vr->YPlacement = GET_Short();
+
+ FORGET_Frame();
+ }
+ else
+ vr->YPlacement = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ vr->XAdvance = GET_Short();
+
+ FORGET_Frame();
+ }
+ else
+ vr->XAdvance = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ vr->YAdvance = GET_Short();
+
+ FORGET_Frame();
+ }
+ else
+ vr->YAdvance = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &vr->XPlacementDevice,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ goto empty1;
+ }
+ else
+ {
+ empty1:
+ vr->XPlacementDevice.StartSize = 0;
+ vr->XPlacementDevice.EndSize = 0;
+ vr->XPlacementDevice.DeltaValue = NULL;
+ }
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &vr->YPlacementDevice,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ goto empty2;
+ }
+ else
+ {
+ empty2:
+ vr->YPlacementDevice.StartSize = 0;
+ vr->YPlacementDevice.EndSize = 0;
+ vr->YPlacementDevice.DeltaValue = NULL;
+ }
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &vr->XAdvanceDevice,
+ stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ goto empty3;
+ }
+ else
+ {
+ empty3:
+ vr->XAdvanceDevice.StartSize = 0;
+ vr->XAdvanceDevice.EndSize = 0;
+ vr->XAdvanceDevice.DeltaValue = NULL;
+ }
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &vr->YAdvanceDevice,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ goto empty4;
+ }
+ else
+ {
+ empty4:
+ vr->YAdvanceDevice.StartSize = 0;
+ vr->YAdvanceDevice.EndSize = 0;
+ vr->YAdvanceDevice.DeltaValue = NULL;
+ }
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ vr->XIdPlacement = GET_UShort();
+
+ FORGET_Frame();
+ }
+ else
+ vr->XIdPlacement = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ vr->YIdPlacement = GET_UShort();
+
+ FORGET_Frame();
+ }
+ else
+ vr->YIdPlacement = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ vr->XIdAdvance = GET_UShort();
+
+ FORGET_Frame();
+ }
+ else
+ vr->XIdAdvance = 0;
+
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ vr->YIdAdvance = GET_UShort();
+
+ FORGET_Frame();
+ }
+ else
+ vr->YIdAdvance = 0;
+
+ return HB_Err_Ok;
+
+Fail1:
+ _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
+
+Fail2:
+ _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
+
+Fail3:
+ _HB_OPEN_Free_Device( &vr->YPlacementDevice );
+ return error;
+}
+
+
+static void Free_ValueRecord( HB_ValueRecord* vr,
+ HB_UShort format )
+{
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
+ _HB_OPEN_Free_Device( &vr->YAdvanceDevice );
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
+ _HB_OPEN_Free_Device( &vr->XAdvanceDevice );
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
+ _HB_OPEN_Free_Device( &vr->YPlacementDevice );
+ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
+ _HB_OPEN_Free_Device( &vr->XPlacementDevice );
+}
+
+
+static HB_Error Get_ValueRecord( GPOS_Instance* gpi,
+ HB_ValueRecord* vr,
+ HB_UShort format,
+ HB_Position gd )
+{
+ HB_Fixed value;
+ HB_Short pixel_value;
+ HB_Error error = HB_Err_Ok;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_UShort x_ppem, y_ppem;
+ HB_16Dot16 x_scale, y_scale;
+
+
+ if ( !format )
+ return HB_Err_Ok;
+
+ x_ppem = gpi->font->x_ppem;
+ y_ppem = gpi->font->y_ppem;
+ x_scale = gpi->font->x_scale;
+ y_scale = gpi->font->y_scale;
+
+ /* design units -> fractional pixel */
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
+ gd->x_pos += x_scale * vr->XPlacement / 0x10000;
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
+ gd->y_pos += y_scale * vr->YPlacement / 0x10000;
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
+ gd->x_advance += x_scale * vr->XAdvance / 0x10000;
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
+ gd->y_advance += y_scale * vr->YAdvance / 0x10000;
+
+ if ( !gpi->dvi )
+ {
+ /* pixel -> fractional pixel */
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
+ {
+ _HB_OPEN_Get_Device( &vr->XPlacementDevice, x_ppem, &pixel_value );
+ gd->x_pos += pixel_value << 6;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
+ {
+ _HB_OPEN_Get_Device( &vr->YPlacementDevice, y_ppem, &pixel_value );
+ gd->y_pos += pixel_value << 6;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
+ {
+ _HB_OPEN_Get_Device( &vr->XAdvanceDevice, x_ppem, &pixel_value );
+ gd->x_advance += pixel_value << 6;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
+ {
+ _HB_OPEN_Get_Device( &vr->YAdvanceDevice, y_ppem, &pixel_value );
+ gd->y_advance += pixel_value << 6;
+ }
+ }
+
+ /* values returned from mmfunc() are already in fractional pixels */
+
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
+ {
+ error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->x_pos += value;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
+ {
+ error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->y_pos += value;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
+ {
+ error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->x_advance += value;
+ }
+ if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
+ {
+ error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
+ &value, gpos->data );
+ if ( error )
+ return error;
+ gd->y_advance += value;
+ }
+
+ return error;
+}
+
+
+/* AnchorFormat1 */
+/* AnchorFormat2 */
+/* AnchorFormat3 */
+/* AnchorFormat4 */
+
+static HB_Error Load_Anchor( HB_Anchor* an,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ an->PosFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( an->PosFormat )
+ {
+ case 1:
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ an->af.af1.XCoordinate = GET_Short();
+ an->af.af1.YCoordinate = GET_Short();
+
+ FORGET_Frame();
+ break;
+
+ case 2:
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ an->af.af2.XCoordinate = GET_Short();
+ an->af.af2.YCoordinate = GET_Short();
+ an->af.af2.AnchorPoint = GET_UShort();
+
+ FORGET_Frame();
+ break;
+
+ case 3:
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ an->af.af3.XCoordinate = GET_Short();
+ an->af.af3.YCoordinate = GET_Short();
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &an->af.af3.XDeviceTable,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ an->af.af3.XDeviceTable.StartSize = 0;
+ an->af.af3.XDeviceTable.EndSize = 0;
+ an->af.af3.XDeviceTable.DeltaValue = NULL;
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Device( &an->af.af3.YDeviceTable,
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ an->af.af3.YDeviceTable.StartSize = 0;
+ an->af.af3.YDeviceTable.EndSize = 0;
+ an->af.af3.YDeviceTable.DeltaValue = NULL;
+ }
+ break;
+
+ case 4:
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ an->af.af4.XIdAnchor = GET_UShort();
+ an->af.af4.YIdAnchor = GET_UShort();
+
+ FORGET_Frame();
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
+ return error;
+}
+
+
+static void Free_Anchor( HB_Anchor* an)
+{
+ if ( an->PosFormat == 3 )
+ {
+ _HB_OPEN_Free_Device( &an->af.af3.YDeviceTable );
+ _HB_OPEN_Free_Device( &an->af.af3.XDeviceTable );
+ }
+}
+
+
+static HB_Error Get_Anchor( GPOS_Instance* gpi,
+ HB_Anchor* an,
+ HB_UShort glyph_index,
+ HB_Fixed* x_value,
+ HB_Fixed* y_value )
+{
+ HB_Error error = HB_Err_Ok;
+
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_UShort ap;
+
+ HB_Short pixel_value;
+
+ HB_UShort x_ppem, y_ppem;
+ HB_16Dot16 x_scale, y_scale;
+
+
+ x_ppem = gpi->font->x_ppem;
+ y_ppem = gpi->font->y_ppem;
+ x_scale = gpi->font->x_scale;
+ y_scale = gpi->font->y_scale;
+
+ switch ( an->PosFormat )
+ {
+ case 0:
+ /* The special case of an empty AnchorTable */
+ default:
+
+ return HB_Err_Not_Covered;
+
+ case 1:
+ *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
+ *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
+ break;
+
+ case 2:
+ if ( !gpi->dvi )
+ {
+ hb_uint32 n_points = 0;
+ ap = an->af.af2.AnchorPoint;
+ if (!gpi->font->klass->getPointInOutline)
+ goto no_contour_point;
+ error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points);
+ if (error)
+ return error;
+ /* if n_points is set to zero, we use the design coordinate value pair.
+ * This can happen e.g. for sbit glyphs. */
+ if (!n_points)
+ goto no_contour_point;
+ }
+ else
+ {
+ no_contour_point:
+ *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
+ *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
+ }
+ break;
+
+ case 3:
+ if ( !gpi->dvi )
+ {
+ _HB_OPEN_Get_Device( &an->af.af3.XDeviceTable, x_ppem, &pixel_value );
+ *x_value = pixel_value << 6;
+ _HB_OPEN_Get_Device( &an->af.af3.YDeviceTable, y_ppem, &pixel_value );
+ *y_value = pixel_value << 6;
+ }
+ else
+ *x_value = *y_value = 0;
+
+ *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
+ *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
+ break;
+
+ case 4:
+ error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
+ x_value, gpos->data );
+ if ( error )
+ return error;
+
+ error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
+ y_value, gpos->data );
+ if ( error )
+ return error;
+ break;
+ }
+
+ return error;
+}
+
+
+/* MarkArray */
+
+static HB_Error Load_MarkArray ( HB_MarkArray* ma,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_MarkRecord* mr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ma->MarkCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ma->MarkRecord = NULL;
+
+ if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
+ return error;
+
+ mr = ma->MarkRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail;
+
+ mr[n].Class = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_Anchor( &mr[m].MarkAnchor );
+
+ FREE( mr );
+ return error;
+}
+
+
+static void Free_MarkArray( HB_MarkArray* ma )
+{
+ HB_UShort n, count;
+
+ HB_MarkRecord* mr;
+
+
+ if ( ma->MarkRecord )
+ {
+ count = ma->MarkCount;
+ mr = ma->MarkRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_Anchor( &mr[n].MarkAnchor );
+
+ FREE( mr );
+ }
+}
+
+
+/* LookupType 1 */
+
+/* SinglePosFormat1 */
+/* SinglePosFormat2 */
+
+static HB_Error Load_SinglePos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_SinglePos* sp = &st->single;
+
+ HB_UShort n, m, count, format;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ValueRecord* vr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ sp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ format = sp->ValueFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( !format )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ switch ( sp->PosFormat )
+ {
+ case 1:
+ error = Load_ValueRecord( &sp->spf.spf1.Value, format,
+ base_offset, stream );
+ if ( error )
+ goto Fail2;
+ break;
+
+ case 2:
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = sp->spf.spf2.ValueCount = GET_UShort();
+
+ FORGET_Frame();
+
+ sp->spf.spf2.Value = NULL;
+
+ if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
+ goto Fail2;
+
+ vr = sp->spf.spf2.Value;
+
+ for ( n = 0; n < count; n++ )
+ {
+ error = Load_ValueRecord( &vr[n], format, base_offset, stream );
+ if ( error )
+ goto Fail1;
+ }
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ValueRecord( &vr[m], format );
+
+ FREE( vr );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &sp->Coverage );
+ return error;
+}
+
+
+static void Free_SinglePos( HB_GPOS_SubTable* st )
+{
+ HB_UShort n, count, format;
+ HB_SinglePos* sp = &st->single;
+
+ HB_ValueRecord* v;
+
+
+ format = sp->ValueFormat;
+
+ switch ( sp->PosFormat )
+ {
+ case 1:
+ Free_ValueRecord( &sp->spf.spf1.Value, format );
+ break;
+
+ case 2:
+ if ( sp->spf.spf2.Value )
+ {
+ count = sp->spf.spf2.ValueCount;
+ v = sp->spf.spf2.Value;
+
+ for ( n = 0; n < count; n++ )
+ Free_ValueRecord( &v[n], format );
+
+ FREE( v );
+ }
+ break;
+ default:
+ break;
+ }
+
+ _HB_OPEN_Free_Coverage( &sp->Coverage );
+}
+
+static HB_Error Lookup_SinglePos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_SinglePos* sp = &st->single;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ switch ( sp->PosFormat )
+ {
+ case 1:
+ error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
+ sp->ValueFormat, POSITION( buffer->in_pos ) );
+ if ( error )
+ return error;
+ break;
+
+ case 2:
+ if ( index >= sp->spf.spf2.ValueCount )
+ return ERR(HB_Err_Invalid_SubTable);
+ error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
+ sp->ValueFormat, POSITION( buffer->in_pos ) );
+ if ( error )
+ return error;
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable);
+ }
+
+ (buffer->in_pos)++;
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 2 */
+
+/* PairSet */
+
+static HB_Error Load_PairSet ( HB_PairSet* ps,
+ HB_UShort format1,
+ HB_UShort format2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt base_offset;
+
+ HB_PairValueRecord* pvr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ps->PairValueCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ps->PairValueRecord = NULL;
+
+ if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
+ return error;
+
+ pvr = ps->PairValueRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ pvr[n].SecondGlyph = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( format1 )
+ {
+ error = Load_ValueRecord( &pvr[n].Value1, format1,
+ base_offset, stream );
+ if ( error )
+ goto Fail;
+ }
+ if ( format2 )
+ {
+ error = Load_ValueRecord( &pvr[n].Value2, format2,
+ base_offset, stream );
+ if ( error )
+ {
+ if ( format1 )
+ Free_ValueRecord( &pvr[n].Value1, format1 );
+ goto Fail;
+ }
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &pvr[m].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &pvr[m].Value2, format2 );
+ }
+
+ FREE( pvr );
+ return error;
+}
+
+
+static void Free_PairSet( HB_PairSet* ps,
+ HB_UShort format1,
+ HB_UShort format2 )
+{
+ HB_UShort n, count;
+
+ HB_PairValueRecord* pvr;
+
+
+ if ( ps->PairValueRecord )
+ {
+ count = ps->PairValueCount;
+ pvr = ps->PairValueRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &pvr[n].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &pvr[n].Value2, format2 );
+ }
+
+ FREE( pvr );
+ }
+}
+
+
+/* PairPosFormat1 */
+
+static HB_Error Load_PairPos1( HB_PairPosFormat1* ppf1,
+ HB_UShort format1,
+ HB_UShort format2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_PairSet* ps;
+
+
+ base_offset = FILE_Pos() - 8L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ppf1->PairSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ppf1->PairSet = NULL;
+
+ if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
+ return error;
+
+ ps = ppf1->PairSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_PairSet( &ps[n], format1,
+ format2, stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_PairSet( &ps[m], format1, format2 );
+
+ FREE( ps );
+ return error;
+}
+
+
+static void Free_PairPos1( HB_PairPosFormat1* ppf1,
+ HB_UShort format1,
+ HB_UShort format2 )
+{
+ HB_UShort n, count;
+
+ HB_PairSet* ps;
+
+
+ if ( ppf1->PairSet )
+ {
+ count = ppf1->PairSetCount;
+ ps = ppf1->PairSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_PairSet( &ps[n], format1, format2 );
+
+ FREE( ps );
+ }
+}
+
+
+/* PairPosFormat2 */
+
+static HB_Error Load_PairPos2( HB_PairPosFormat2* ppf2,
+ HB_UShort format1,
+ HB_UShort format2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort m, n, k, count1, count2;
+ HB_UInt cur_offset, new_offset1, new_offset2, base_offset;
+
+ HB_Class1Record* c1r;
+ HB_Class2Record* c2r;
+
+
+ base_offset = FILE_Pos() - 8L;
+
+ if ( ACCESS_Frame( 8L ) )
+ return error;
+
+ new_offset1 = GET_UShort() + base_offset;
+ new_offset2 = GET_UShort() + base_offset;
+
+ /* `Class1Count' and `Class2Count' are the upper limits for class
+ values, thus we read it now to make additional safety checks. */
+
+ count1 = ppf2->Class1Count = GET_UShort();
+ count2 = ppf2->Class2Count = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset1 ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ if ( FILE_Seek( new_offset2 ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ ppf2->Class1Record = NULL;
+
+ if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
+ goto Fail2;
+
+ c1r = ppf2->Class1Record;
+
+ for ( m = 0; m < count1; m++ )
+ {
+ c1r[m].Class2Record = NULL;
+
+ if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
+ goto Fail1;
+
+ c2r = c1r[m].Class2Record;
+
+ for ( n = 0; n < count2; n++ )
+ {
+ if ( format1 )
+ {
+ error = Load_ValueRecord( &c2r[n].Value1, format1,
+ base_offset, stream );
+ if ( error )
+ goto Fail0;
+ }
+ if ( format2 )
+ {
+ error = Load_ValueRecord( &c2r[n].Value2, format2,
+ base_offset, stream );
+ if ( error )
+ {
+ if ( format1 )
+ Free_ValueRecord( &c2r[n].Value1, format1 );
+ goto Fail0;
+ }
+ }
+ }
+
+ continue;
+
+ Fail0:
+ for ( k = 0; k < n; k++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &c2r[k].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &c2r[k].Value2, format2 );
+ }
+ goto Fail1;
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( k = 0; k < m; k++ )
+ {
+ c2r = c1r[k].Class2Record;
+
+ for ( n = 0; n < count2; n++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &c2r[n].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &c2r[n].Value2, format2 );
+ }
+
+ FREE( c2r );
+ }
+
+ FREE( c1r );
+Fail2:
+
+ _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
+
+Fail3:
+ _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
+ return error;
+}
+
+
+static void Free_PairPos2( HB_PairPosFormat2* ppf2,
+ HB_UShort format1,
+ HB_UShort format2)
+{
+ HB_UShort m, n, count1, count2;
+
+ HB_Class1Record* c1r;
+ HB_Class2Record* c2r;
+
+
+ if ( ppf2->Class1Record )
+ {
+ c1r = ppf2->Class1Record;
+ count1 = ppf2->Class1Count;
+ count2 = ppf2->Class2Count;
+
+ for ( m = 0; m < count1; m++ )
+ {
+ c2r = c1r[m].Class2Record;
+
+ for ( n = 0; n < count2; n++ )
+ {
+ if ( format1 )
+ Free_ValueRecord( &c2r[n].Value1, format1 );
+ if ( format2 )
+ Free_ValueRecord( &c2r[n].Value2, format2 );
+ }
+
+ FREE( c2r );
+ }
+
+ FREE( c1r );
+
+ _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
+ _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
+ }
+}
+
+
+static HB_Error Load_PairPos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_PairPos* pp = &st->pair;
+
+ HB_UShort format1, format2;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 8L ) )
+ return error;
+
+ pp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ format1 = pp->ValueFormat1 = GET_UShort();
+ format2 = pp->ValueFormat2 = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
+ if ( error )
+ goto Fail;
+ break;
+
+ case 2:
+ error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
+ if ( error )
+ goto Fail;
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ _HB_OPEN_Free_Coverage( &pp->Coverage );
+ return error;
+}
+
+
+static void Free_PairPos( HB_GPOS_SubTable* st )
+{
+ HB_UShort format1, format2;
+ HB_PairPos* pp = &st->pair;
+
+
+ format1 = pp->ValueFormat1;
+ format2 = pp->ValueFormat2;
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
+ break;
+
+ case 2:
+ Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
+ break;
+
+ default:
+ break;
+ }
+
+ _HB_OPEN_Free_Coverage( &pp->Coverage );
+}
+
+
+static HB_Error Lookup_PairPos1( GPOS_Instance* gpi,
+ HB_PairPosFormat1* ppf1,
+ HB_Buffer buffer,
+ HB_UInt first_pos,
+ HB_UShort index,
+ HB_UShort format1,
+ HB_UShort format2 )
+{
+ HB_Error error;
+ HB_UShort numpvr, glyph2;
+
+ HB_PairValueRecord* pvr;
+
+
+ if ( index >= ppf1->PairSetCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ pvr = ppf1->PairSet[index].PairValueRecord;
+ if ( !pvr )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ glyph2 = IN_CURGLYPH();
+
+ for ( numpvr = ppf1->PairSet[index].PairValueCount;
+ numpvr;
+ numpvr--, pvr++ )
+ {
+ if ( glyph2 == pvr->SecondGlyph )
+ {
+ error = Get_ValueRecord( gpi, &pvr->Value1, format1,
+ POSITION( first_pos ) );
+ if ( error )
+ return error;
+ return Get_ValueRecord( gpi, &pvr->Value2, format2,
+ POSITION( buffer->in_pos ) );
+ }
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_PairPos2( GPOS_Instance* gpi,
+ HB_PairPosFormat2* ppf2,
+ HB_Buffer buffer,
+ HB_UInt first_pos,
+ HB_UShort format1,
+ HB_UShort format2 )
+{
+ HB_Error error;
+ HB_UShort cl1 = 0, cl2 = 0; /* shut compiler up */
+
+ HB_Class1Record* c1r;
+ HB_Class2Record* c2r;
+
+
+ error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
+ &cl1, NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
+ &cl2, NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ c1r = &ppf2->Class1Record[cl1];
+ if ( !c1r )
+ return ERR(HB_Err_Invalid_SubTable);
+ c2r = &c1r->Class2Record[cl2];
+
+ error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
+ if ( error )
+ return error;
+ return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
+}
+
+
+static HB_Error Lookup_PairPos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, property;
+ HB_UInt first_pos;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_PairPos* pp = &st->pair;
+
+ HB_UNUSED(nesting_level);
+
+ if ( buffer->in_pos >= buffer->in_length - 1 )
+ return HB_Err_Not_Covered; /* Not enough glyphs in stream */
+
+ if ( context_length != 0xFFFF && context_length < 2 )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ /* second glyph */
+
+ first_pos = buffer->in_pos;
+ (buffer->in_pos)++;
+
+ while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+ flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( buffer->in_pos == buffer->in_length )
+ {
+ buffer->in_pos = first_pos;
+ return HB_Err_Not_Covered;
+ }
+ (buffer->in_pos)++;
+
+ }
+
+ switch ( pp->PosFormat )
+ {
+ case 1:
+ error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
+ first_pos, index,
+ pp->ValueFormat1, pp->ValueFormat2 );
+ break;
+
+ case 2:
+ error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
+ pp->ValueFormat1, pp->ValueFormat2 );
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ /* if we don't have coverage for the second glyph don't skip it for
+ further lookups but reset in_pos back to the first_glyph and let
+ the caller in Do_String_Lookup increment in_pos */
+ if ( error == HB_Err_Not_Covered )
+ buffer->in_pos = first_pos;
+
+ /* adjusting the `next' glyph */
+
+ if ( pp->ValueFormat2 )
+ (buffer->in_pos)++;
+
+ return error;
+}
+
+
+/* LookupType 3 */
+
+/* CursivePosFormat1 */
+
+static HB_Error Load_CursivePos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_CursivePos* cp = &st->cursive;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_EntryExitRecord* eer;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ cp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = cp->EntryExitCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cp->EntryExitRecord = NULL;
+
+ if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
+ goto Fail2;
+
+ eer = cp->EntryExitRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ HB_UInt entry_offset;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ entry_offset = new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &eer[n].EntryAnchor,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ eer[n].EntryAnchor.PosFormat = 0;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &eer[n].ExitAnchor,
+ stream ) ) != HB_Err_Ok )
+ {
+ if ( entry_offset )
+ Free_Anchor( &eer[n].EntryAnchor );
+ goto Fail1;
+ }
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ eer[n].ExitAnchor.PosFormat = 0;
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ {
+ Free_Anchor( &eer[m].EntryAnchor );
+ Free_Anchor( &eer[m].ExitAnchor );
+ }
+
+ FREE( eer );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &cp->Coverage );
+ return error;
+}
+
+
+static void Free_CursivePos( HB_GPOS_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_CursivePos* cp = &st->cursive;
+
+ HB_EntryExitRecord* eer;
+
+
+ if ( cp->EntryExitRecord )
+ {
+ count = cp->EntryExitCount;
+ eer = cp->EntryExitRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ Free_Anchor( &eer[n].EntryAnchor );
+ Free_Anchor( &eer[n].ExitAnchor );
+ }
+
+ FREE( eer );
+ }
+
+ _HB_OPEN_Free_Coverage( &cp->Coverage );
+}
+
+
+static HB_Error Lookup_CursivePos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_CursivePos* cp = &st->cursive;
+
+ HB_EntryExitRecord* eer;
+ HB_Fixed entry_x, entry_y;
+ HB_Fixed exit_x, exit_y;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ {
+ gpi->last = 0xFFFF;
+ return HB_Err_Not_Covered;
+ }
+
+ /* Glyphs not having the right GDEF properties will be ignored, i.e.,
+ gpi->last won't be reset (contrary to user defined properties). */
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ /* We don't handle mark glyphs here. According to Andrei, this isn't
+ possible, but who knows... */
+
+ if ( property == HB_GDEF_MARK )
+ {
+ gpi->last = 0xFFFF;
+ return HB_Err_Not_Covered;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ {
+ gpi->last = 0xFFFF;
+ return error;
+ }
+
+ if ( index >= cp->EntryExitCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ eer = &cp->EntryExitRecord[index];
+
+ /* Now comes the messiest part of the whole OpenType
+ specification. At first glance, cursive connections seem easy
+ to understand, but there are pitfalls! The reason is that
+ the specs don't mention how to compute the advance values
+ resp. glyph offsets. I was told it would be an omission, to
+ be fixed in the next OpenType version... Again many thanks to
+ Andrei Burago <andreib@microsoft.com> for clarifications.
+
+ Consider the following example:
+
+ | xadv1 |
+ +---------+
+ | |
+ +-----+--+ 1 |
+ | | .| |
+ | 0+--+------+
+ | 2 |
+ | |
+ 0+--------+
+ | xadv2 |
+
+ glyph1: advance width = 12
+ anchor point = (3,1)
+
+ glyph2: advance width = 11
+ anchor point = (9,4)
+
+ LSB is 1 for both glyphs (so the boxes drawn above are glyph
+ bboxes). Writing direction is R2L; `0' denotes the glyph's
+ coordinate origin.
+
+ Now the surprising part: The advance width of the *left* glyph
+ (resp. of the *bottom* glyph) will be modified, no matter
+ whether the writing direction is L2R or R2L (resp. T2B or
+ B2T)! This assymetry is caused by the fact that the glyph's
+ coordinate origin is always the lower left corner for all
+ writing directions.
+
+ Continuing the above example, we can compute the new
+ (horizontal) advance width of glyph2 as
+
+ 9 - 3 = 6 ,
+
+ and the new vertical offset of glyph2 as
+
+ 1 - 4 = -3 .
+
+
+ Vertical writing direction is far more complicated:
+
+ a) Assuming that we recompute the advance height of the lower glyph:
+
+ --
+ +---------+
+ -- | |
+ +-----+--+ 1 | yadv1
+ | | .| |
+ yadv2 | 0+--+------+ -- BSB1 --
+ | 2 | -- -- y_offset
+ | |
+ BSB2 -- 0+--------+ --
+ -- --
+
+ glyph1: advance height = 6
+ anchor point = (3,1)
+
+ glyph2: advance height = 7
+ anchor point = (9,4)
+
+ TSB is 1 for both glyphs; writing direction is T2B.
+
+
+ BSB1 = yadv1 - (TSB1 + ymax1)
+ BSB2 = yadv2 - (TSB2 + ymax2)
+ y_offset = y2 - y1
+
+ vertical advance width of glyph2
+ = y_offset + BSB2 - BSB1
+ = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
+ = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
+ = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
+
+
+ b) Assuming that we recompute the advance height of the upper glyph:
+
+ -- --
+ +---------+ -- TSB1
+ -- -- | |
+ TSB2 -- +-----+--+ 1 | yadv1 ymax1
+ | | .| |
+ yadv2 | 0+--+------+ -- --
+ ymax2 | 2 | -- y_offset
+ | |
+ -- 0+--------+ --
+ --
+
+ glyph1: advance height = 6
+ anchor point = (3,1)
+
+ glyph2: advance height = 7
+ anchor point = (9,4)
+
+ TSB is 1 for both glyphs; writing direction is T2B.
+
+ y_offset = y2 - y1
+
+ vertical advance width of glyph2
+ = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
+ = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
+
+
+ Comparing a) with b) shows that b) is easier to compute. I'll wait
+ for a reply from Andrei to see what should really be implemented...
+
+ Since horizontal advance widths or vertical advance heights
+ can be used alone but not together, no ambiguity occurs. */
+
+ if ( gpi->last == 0xFFFF )
+ goto end;
+
+ /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
+ table. */
+
+ error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
+ &entry_x, &entry_y );
+ if ( error == HB_Err_Not_Covered )
+ goto end;
+ if ( error )
+ return error;
+
+ if ( gpi->r2l )
+ {
+ POSITION( buffer->in_pos )->x_advance = entry_x - gpi->anchor_x;
+ POSITION( buffer->in_pos )->new_advance = TRUE;
+ }
+ else
+ {
+ POSITION( gpi->last )->x_advance = gpi->anchor_x - entry_x;
+ POSITION( gpi->last )->new_advance = TRUE;
+ }
+
+ if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
+ {
+ POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
+ POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
+ }
+ else
+ {
+ POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
+ POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
+ }
+
+end:
+ error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
+ &exit_x, &exit_y );
+ if ( error == HB_Err_Not_Covered )
+ gpi->last = 0xFFFF;
+ else
+ {
+ gpi->last = buffer->in_pos;
+ gpi->anchor_x = exit_x;
+ gpi->anchor_y = exit_y;
+ }
+ if ( error )
+ return error;
+
+ (buffer->in_pos)++;
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 4 */
+
+/* BaseArray */
+
+static HB_Error Load_BaseArray( HB_BaseArray* ba,
+ HB_UShort num_classes,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort m, n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_BaseRecord *br;
+ HB_Anchor *ban, *bans;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ba->BaseCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ba->BaseRecord = NULL;
+
+ if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
+ return error;
+
+ br = ba->BaseRecord;
+
+ bans = NULL;
+
+ if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
+ goto Fail;
+
+ for ( m = 0; m < count; m++ )
+ {
+ br[m].BaseAnchor = NULL;
+
+ ban = br[m].BaseAnchor = bans + m * num_classes;
+
+ for ( n = 0; n < num_classes; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if (new_offset == base_offset) {
+ /* XXX
+ * Doulos SIL Regular is buggy and has zero offsets here.
+ * Skip it
+ */
+ ban[n].PosFormat = 0;
+ continue;
+ }
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( bans );
+ FREE( br );
+ return error;
+}
+
+
+static void Free_BaseArray( HB_BaseArray* ba,
+ HB_UShort num_classes )
+{
+ HB_BaseRecord *br;
+ HB_Anchor *bans;
+
+ HB_UNUSED(num_classes);
+
+ if ( ba->BaseRecord )
+ {
+ br = ba->BaseRecord;
+
+ if ( ba->BaseCount )
+ {
+ bans = br[0].BaseAnchor;
+ FREE( bans );
+ }
+
+ FREE( br );
+ }
+}
+
+
+/* MarkBasePosFormat1 */
+
+static HB_Error Load_MarkBasePos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_MarkBasePos* mbp = &st->markbase;
+
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ mbp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if (mbp->PosFormat != 1)
+ return ERR(HB_Err_Invalid_SubTable_Format);
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail2;
+
+ mbp->ClassCount = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+
+ return HB_Err_Ok;
+
+Fail1:
+ Free_MarkArray( &mbp->MarkArray );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
+ return error;
+}
+
+
+static void Free_MarkBasePos( HB_GPOS_SubTable* st )
+{
+ HB_MarkBasePos* mbp = &st->markbase;
+
+ Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
+ Free_MarkArray( &mbp->MarkArray );
+ _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
+ _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
+}
+
+
+static HB_Error Lookup_MarkBasePos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort i, j, mark_index, base_index, property, class;
+ HB_Fixed x_mark_value, y_mark_value, x_base_value, y_base_value;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_MarkBasePos* mbp = &st->markbase;
+
+ HB_MarkArray* ma;
+ HB_BaseArray* ba;
+ HB_BaseRecord* br;
+ HB_Anchor* mark_anchor;
+ HB_Anchor* base_anchor;
+
+ HB_Position o;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+ flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
+ &mark_index );
+ if ( error )
+ return error;
+
+ /* now we search backwards for a non-mark glyph */
+
+ i = 1;
+ j = buffer->in_pos - 1;
+
+ while ( i <= buffer->in_pos )
+ {
+ error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+ &property );
+ if ( error )
+ return error;
+
+ if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+ break;
+
+ i++;
+ j--;
+ }
+
+ /* The following assertion is too strong -- at least for mangal.ttf. */
+#if 0
+ if ( property != HB_GDEF_BASE_GLYPH )
+ return HB_Err_Not_Covered;
+#endif
+
+ if ( i > buffer->in_pos )
+ return HB_Err_Not_Covered;
+
+ error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
+ &base_index );
+ if ( error )
+ return error;
+
+ ma = &mbp->MarkArray;
+
+ if ( mark_index >= ma->MarkCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ class = ma->MarkRecord[mark_index].Class;
+ mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
+
+ if ( class >= mbp->ClassCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ ba = &mbp->BaseArray;
+
+ if ( base_index >= ba->BaseCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ br = &ba->BaseRecord[base_index];
+ base_anchor = &br->BaseAnchor[class];
+
+ error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
+ &x_mark_value, &y_mark_value );
+ if ( error )
+ return error;
+
+ error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
+ &x_base_value, &y_base_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = POSITION( buffer->in_pos );
+
+ o->x_pos = x_base_value - x_mark_value;
+ o->y_pos = y_base_value - y_mark_value;
+ o->x_advance = 0;
+ o->y_advance = 0;
+ o->back = i;
+
+ (buffer->in_pos)++;
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 5 */
+
+/* LigatureAttach */
+
+static HB_Error Load_LigatureAttach( HB_LigatureAttach* lat,
+ HB_UShort num_classes,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort m, n, k, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ComponentRecord* cr;
+ HB_Anchor* lan;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = lat->ComponentCount = GET_UShort();
+
+ FORGET_Frame();
+
+ lat->ComponentRecord = NULL;
+
+ if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
+ return error;
+
+ cr = lat->ComponentRecord;
+
+ for ( m = 0; m < count; m++ )
+ {
+ cr[m].LigatureAnchor = NULL;
+
+ if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
+ goto Fail;
+
+ lan = cr[m].LigatureAnchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail0;
+
+ new_offset = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( new_offset )
+ {
+ new_offset += base_offset;
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
+ goto Fail0;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ lan[n].PosFormat = 0;
+ }
+
+ continue;
+ Fail0:
+ for ( k = 0; k < n; k++ )
+ Free_Anchor( &lan[k] );
+ goto Fail;
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( k = 0; k < m; k++ )
+ {
+ lan = cr[k].LigatureAnchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ Free_Anchor( &lan[n] );
+
+ FREE( lan );
+ }
+
+ FREE( cr );
+ return error;
+}
+
+
+static void Free_LigatureAttach( HB_LigatureAttach* lat,
+ HB_UShort num_classes )
+{
+ HB_UShort m, n, count;
+
+ HB_ComponentRecord* cr;
+ HB_Anchor* lan;
+
+
+ if ( lat->ComponentRecord )
+ {
+ count = lat->ComponentCount;
+ cr = lat->ComponentRecord;
+
+ for ( m = 0; m < count; m++ )
+ {
+ lan = cr[m].LigatureAnchor;
+
+ for ( n = 0; n < num_classes; n++ )
+ Free_Anchor( &lan[n] );
+
+ FREE( lan );
+ }
+
+ FREE( cr );
+ }
+}
+
+
+/* LigatureArray */
+
+static HB_Error Load_LigatureArray( HB_LigatureArray* la,
+ HB_UShort num_classes,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LigatureAttach* lat;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = la->LigatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ la->LigatureAttach = NULL;
+
+ if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
+ return error;
+
+ lat = la->LigatureAttach;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LigatureAttach( &lat[n], num_classes,
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_LigatureAttach( &lat[m], num_classes );
+
+ FREE( lat );
+ return error;
+}
+
+
+static void Free_LigatureArray( HB_LigatureArray* la,
+ HB_UShort num_classes )
+{
+ HB_UShort n, count;
+
+ HB_LigatureAttach* lat;
+
+
+ if ( la->LigatureAttach )
+ {
+ count = la->LigatureCount;
+ lat = la->LigatureAttach;
+
+ for ( n = 0; n < count; n++ )
+ Free_LigatureAttach( &lat[n], num_classes );
+
+ FREE( lat );
+ }
+}
+
+
+/* MarkLigPosFormat1 */
+
+static HB_Error Load_MarkLigPos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_MarkLigPos* mlp = &st->marklig;
+
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ mlp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail2;
+
+ mlp->ClassCount = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+
+ return HB_Err_Ok;
+
+Fail1:
+ Free_MarkArray( &mlp->MarkArray );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
+ return error;
+}
+
+
+static void Free_MarkLigPos( HB_GPOS_SubTable* st)
+{
+ HB_MarkLigPos* mlp = &st->marklig;
+
+ Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
+ Free_MarkArray( &mlp->MarkArray );
+ _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
+ _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
+}
+
+
+static HB_Error Lookup_MarkLigPos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort i, j, mark_index, lig_index, property, class;
+ HB_UShort mark_glyph;
+ HB_Fixed x_mark_value, y_mark_value, x_lig_value, y_lig_value;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_MarkLigPos* mlp = &st->marklig;
+
+ HB_MarkArray* ma;
+ HB_LigatureArray* la;
+ HB_LigatureAttach* lat;
+ HB_ComponentRecord* cr;
+ HB_UShort comp_index;
+ HB_Anchor* mark_anchor;
+ HB_Anchor* lig_anchor;
+
+ HB_Position o;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
+ return HB_Err_Not_Covered;
+
+ mark_glyph = IN_CURGLYPH();
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
+ if ( error )
+ return error;
+
+ /* now we search backwards for a non-mark glyph */
+
+ i = 1;
+ j = buffer->in_pos - 1;
+
+ while ( i <= buffer->in_pos )
+ {
+ error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+ &property );
+ if ( error )
+ return error;
+
+ if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+ break;
+
+ i++;
+ j--;
+ }
+
+ /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
+ too strong, thus it is commented out. */
+#if 0
+ if ( property != HB_GDEF_LIGATURE )
+ return HB_Err_Not_Covered;
+#endif
+
+ if ( i > buffer->in_pos )
+ return HB_Err_Not_Covered;
+
+ error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
+ &lig_index );
+ if ( error )
+ return error;
+
+ ma = &mlp->MarkArray;
+
+ if ( mark_index >= ma->MarkCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ class = ma->MarkRecord[mark_index].Class;
+ mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
+
+ if ( class >= mlp->ClassCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ la = &mlp->LigatureArray;
+
+ if ( lig_index >= la->LigatureCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ lat = &la->LigatureAttach[lig_index];
+
+ /* We must now check whether the ligature ID of the current mark glyph
+ is identical to the ligature ID of the found ligature. If yes, we
+ can directly use the component index. If not, we attach the mark
+ glyph to the last component of the ligature. */
+
+ if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
+ {
+ comp_index = IN_COMPONENT( buffer->in_pos );
+ if ( comp_index >= lat->ComponentCount )
+ return HB_Err_Not_Covered;
+ }
+ else
+ comp_index = lat->ComponentCount - 1;
+
+ cr = &lat->ComponentRecord[comp_index];
+ lig_anchor = &cr->LigatureAnchor[class];
+
+ error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
+ &x_mark_value, &y_mark_value );
+ if ( error )
+ return error;
+ error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
+ &x_lig_value, &y_lig_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = POSITION( buffer->in_pos );
+
+ o->x_pos = x_lig_value - x_mark_value;
+ o->y_pos = y_lig_value - y_mark_value;
+ o->x_advance = 0;
+ o->y_advance = 0;
+ o->back = i;
+
+ (buffer->in_pos)++;
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 6 */
+
+/* Mark2Array */
+
+static HB_Error Load_Mark2Array( HB_Mark2Array* m2a,
+ HB_UShort num_classes,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort k, m, n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Mark2Record *m2r;
+ HB_Anchor *m2an, *m2ans;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = m2a->Mark2Count = GET_UShort();
+
+ FORGET_Frame();
+
+ m2a->Mark2Record = NULL;
+
+ if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
+ return error;
+
+ m2r = m2a->Mark2Record;
+
+ m2ans = NULL;
+
+ if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
+ goto Fail;
+
+ for ( m = 0; m < count; m++ )
+ {
+ m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
+
+ for ( n = 0; n < num_classes; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if (new_offset == base_offset) {
+ /* Anchor table not provided. Skip loading.
+ * Some versions of FreeSans hit this. */
+ m2an[n].PosFormat = 0;
+ continue;
+ }
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( m2ans );
+ FREE( m2r );
+ return error;
+}
+
+
+static void Free_Mark2Array( HB_Mark2Array* m2a,
+ HB_UShort num_classes )
+{
+ HB_Mark2Record *m2r;
+ HB_Anchor *m2ans;
+
+ HB_UNUSED(num_classes);
+
+ if ( m2a->Mark2Record )
+ {
+ m2r = m2a->Mark2Record;
+
+ if ( m2a->Mark2Count )
+ {
+ m2ans = m2r[0].Mark2Anchor;
+ FREE( m2ans );
+ }
+
+ FREE( m2r );
+ }
+}
+
+
+/* MarkMarkPosFormat1 */
+
+static HB_Error Load_MarkMarkPos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_MarkMarkPos* mmp = &st->markmark;
+
+ HB_UInt cur_offset, new_offset, base_offset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ mmp->PosFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail2;
+
+ mmp->ClassCount = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+
+ return HB_Err_Ok;
+
+Fail1:
+ Free_MarkArray( &mmp->Mark1Array );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
+ return error;
+}
+
+
+static void Free_MarkMarkPos( HB_GPOS_SubTable* st)
+{
+ HB_MarkMarkPos* mmp = &st->markmark;
+
+ Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
+ Free_MarkArray( &mmp->Mark1Array );
+ _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
+ _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
+}
+
+
+static HB_Error Lookup_MarkMarkPos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort i, j, mark1_index, mark2_index, property, class;
+ HB_Fixed x_mark1_value, y_mark1_value,
+ x_mark2_value, y_mark2_value;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_MarkMarkPos* mmp = &st->markmark;
+
+ HB_MarkArray* ma1;
+ HB_Mark2Array* ma2;
+ HB_Mark2Record* m2r;
+ HB_Anchor* mark1_anchor;
+ HB_Anchor* mark2_anchor;
+
+ HB_Position o;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
+ flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
+ &mark1_index );
+ if ( error )
+ return error;
+
+ /* now we search backwards for a suitable mark glyph until a non-mark
+ glyph */
+
+ if ( buffer->in_pos == 0 )
+ return HB_Err_Not_Covered;
+
+ i = 1;
+ j = buffer->in_pos - 1;
+ while ( i <= buffer->in_pos )
+ {
+ error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
+ &property );
+ if ( error )
+ return error;
+
+ if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+ return HB_Err_Not_Covered;
+
+ if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+ {
+ if ( property == (flags & 0xFF00) )
+ break;
+ }
+ else
+ break;
+
+ i++;
+ j--;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
+ &mark2_index );
+ if ( error )
+ return error;
+
+ ma1 = &mmp->Mark1Array;
+
+ if ( mark1_index >= ma1->MarkCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ class = ma1->MarkRecord[mark1_index].Class;
+ mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
+
+ if ( class >= mmp->ClassCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ ma2 = &mmp->Mark2Array;
+
+ if ( mark2_index >= ma2->Mark2Count )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ m2r = &ma2->Mark2Record[mark2_index];
+ mark2_anchor = &m2r->Mark2Anchor[class];
+
+ error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
+ &x_mark1_value, &y_mark1_value );
+ if ( error )
+ return error;
+ error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
+ &x_mark2_value, &y_mark2_value );
+ if ( error )
+ return error;
+
+ /* anchor points are not cumulative */
+
+ o = POSITION( buffer->in_pos );
+
+ o->x_pos = x_mark2_value - x_mark1_value;
+ o->y_pos = y_mark2_value - y_mark1_value;
+ o->x_advance = 0;
+ o->y_advance = 0;
+ o->back = 1;
+
+ (buffer->in_pos)++;
+
+ return HB_Err_Ok;
+}
+
+
+/* Do the actual positioning for a context positioning (either format
+ 7 or 8). This is only called after we've determined that the stream
+ matches the subrule. */
+
+static HB_Error Do_ContextPos( GPOS_Instance* gpi,
+ HB_UShort GlyphCount,
+ HB_UShort PosCount,
+ HB_PosLookupRecord* pos,
+ HB_Buffer buffer,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UInt i, old_pos;
+
+
+ i = 0;
+
+ while ( i < GlyphCount )
+ {
+ if ( PosCount && i == pos->SequenceIndex )
+ {
+ old_pos = buffer->in_pos;
+
+ /* Do a positioning */
+
+ error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
+ GlyphCount, nesting_level );
+
+ if ( error )
+ return error;
+
+ pos++;
+ PosCount--;
+ i += buffer->in_pos - old_pos;
+ }
+ else
+ {
+ i++;
+ (buffer->in_pos)++;
+ }
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 7 */
+
+/* PosRule */
+
+static HB_Error Load_PosRule( HB_PosRule* pr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* i;
+
+ HB_PosLookupRecord* plr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ pr->GlyphCount = GET_UShort();
+ pr->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ pr->Input = NULL;
+
+ count = pr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
+ return error;
+
+ i = pr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ pr->PosLookupRecord = NULL;
+
+ count = pr->PosCount;
+
+ if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = pr->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ FREE( i );
+ return error;
+}
+
+
+static void Free_PosRule( HB_PosRule* pr )
+{
+ FREE( pr->PosLookupRecord );
+ FREE( pr->Input );
+}
+
+
+/* PosRuleSet */
+
+static HB_Error Load_PosRuleSet( HB_PosRuleSet* prs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_PosRule* pr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = prs->PosRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ prs->PosRule = NULL;
+
+ if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
+ return error;
+
+ pr = prs->PosRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_PosRule( &pr[m] );
+
+ FREE( pr );
+ return error;
+}
+
+
+static void Free_PosRuleSet( HB_PosRuleSet* prs )
+{
+ HB_UShort n, count;
+
+ HB_PosRule* pr;
+
+
+ if ( prs->PosRule )
+ {
+ count = prs->PosRuleCount;
+ pr = prs->PosRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_PosRule( &pr[n] );
+
+ FREE( pr );
+ }
+}
+
+
+/* ContextPosFormat1 */
+
+static HB_Error Load_ContextPos1( HB_ContextPosFormat1* cpf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_PosRuleSet* prs;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = cpf1->PosRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpf1->PosRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
+ goto Fail2;
+
+ prs = cpf1->PosRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_PosRuleSet( &prs[m] );
+
+ FREE( prs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &cpf1->Coverage );
+ return error;
+}
+
+
+static void Free_ContextPos1( HB_ContextPosFormat1* cpf1 )
+{
+ HB_UShort n, count;
+
+ HB_PosRuleSet* prs;
+
+
+ if ( cpf1->PosRuleSet )
+ {
+ count = cpf1->PosRuleSetCount;
+ prs = cpf1->PosRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_PosRuleSet( &prs[n] );
+
+ FREE( prs );
+ }
+
+ _HB_OPEN_Free_Coverage( &cpf1->Coverage );
+}
+
+
+/* PosClassRule */
+
+static HB_Error Load_PosClassRule( HB_ContextPosFormat2* cpf2,
+ HB_PosClassRule* pcr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* c;
+ HB_PosLookupRecord* plr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ pcr->GlyphCount = GET_UShort();
+ pcr->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( pcr->GlyphCount > cpf2->MaxContextLength )
+ cpf2->MaxContextLength = pcr->GlyphCount;
+
+ pcr->Class = NULL;
+
+ count = pcr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
+ return error;
+
+ c = pcr->Class;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ c[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ pcr->PosLookupRecord = NULL;
+
+ count = pcr->PosCount;
+
+ if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = pcr->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ FREE( c );
+ return error;
+}
+
+
+static void Free_PosClassRule( HB_PosClassRule* pcr )
+{
+ FREE( pcr->PosLookupRecord );
+ FREE( pcr->Class );
+}
+
+
+/* PosClassSet */
+
+static HB_Error Load_PosClassSet( HB_ContextPosFormat2* cpf2,
+ HB_PosClassSet* pcs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_PosClassRule* pcr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = pcs->PosClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ pcs->PosClassRule = NULL;
+
+ if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
+ return error;
+
+ pcr = pcs->PosClassRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_PosClassRule( cpf2, &pcr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_PosClassRule( &pcr[m] );
+
+ FREE( pcr );
+ return error;
+}
+
+
+static void Free_PosClassSet( HB_PosClassSet* pcs )
+{
+ HB_UShort n, count;
+
+ HB_PosClassRule* pcr;
+
+
+ if ( pcs->PosClassRule )
+ {
+ count = pcs->PosClassRuleCount;
+ pcr = pcs->PosClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_PosClassRule( &pcr[n] );
+
+ FREE( pcr );
+ }
+}
+
+
+/* ContextPosFormat2 */
+
+static HB_Error Load_ContextPos2( HB_ContextPosFormat2* cpf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_PosClassSet* pcs;
+
+
+ base_offset = FILE_Pos() - 2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ /* `PosClassSetCount' is the upper limit for class values, thus we
+ read it now to make an additional safety check. */
+
+ count = cpf2->PosClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ cpf2->PosClassSet = NULL;
+ cpf2->MaxContextLength = 0;
+
+ if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
+ goto Fail2;
+
+ pcs = cpf2->PosClassSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if ( new_offset != base_offset ) /* not a NULL offset */
+ {
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_PosClassSet( cpf2, &pcs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a PosClassSet table with no entries */
+
+ cpf2->PosClassSet[n].PosClassRuleCount = 0;
+ cpf2->PosClassSet[n].PosClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; n++ )
+ Free_PosClassSet( &pcs[m] );
+
+ FREE( pcs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &cpf2->Coverage );
+ return error;
+}
+
+
+static void Free_ContextPos2( HB_ContextPosFormat2* cpf2 )
+{
+ HB_UShort n, count;
+
+ HB_PosClassSet* pcs;
+
+
+ if ( cpf2->PosClassSet )
+ {
+ count = cpf2->PosClassSetCount;
+ pcs = cpf2->PosClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_PosClassSet( &pcs[n] );
+
+ FREE( pcs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
+ _HB_OPEN_Free_Coverage( &cpf2->Coverage );
+}
+
+
+/* ContextPosFormat3 */
+
+static HB_Error Load_ContextPos3( HB_ContextPosFormat3* cpf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* c;
+ HB_PosLookupRecord* plr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ cpf3->GlyphCount = GET_UShort();
+ cpf3->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpf3->Coverage = NULL;
+
+ count = cpf3->GlyphCount;
+
+ if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
+ return error;
+
+ c = cpf3->Coverage;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ cpf3->PosLookupRecord = NULL;
+
+ count = cpf3->PosCount;
+
+ if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = cpf3->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ return error;
+}
+
+
+static void Free_ContextPos3( HB_ContextPosFormat3* cpf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( cpf3->PosLookupRecord );
+
+ if ( cpf3->Coverage )
+ {
+ count = cpf3->GlyphCount;
+ c = cpf3->Coverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ContextPos */
+
+static HB_Error Load_ContextPos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ContextPos* cp = &st->context;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cp->PosFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cp->PosFormat )
+ {
+ case 1:
+ return Load_ContextPos1( &cp->cpf.cpf1, stream );
+
+ case 2:
+ return Load_ContextPos2( &cp->cpf.cpf2, stream );
+
+ case 3:
+ return Load_ContextPos3( &cp->cpf.cpf3, stream );
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ContextPos( HB_GPOS_SubTable* st )
+{
+ HB_ContextPos* cp = &st->context;
+
+ switch ( cp->PosFormat )
+ {
+ case 1: Free_ContextPos1( &cp->cpf.cpf1 ); break;
+ case 2: Free_ContextPos2( &cp->cpf.cpf2 ); break;
+ case 3: Free_ContextPos3( &cp->cpf.cpf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ContextPos1( GPOS_Instance* gpi,
+ HB_ContextPosFormat1* cpf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, numpr;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_PosRule* pr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ pr = cpf1->PosRuleSet[index].PosRule;
+ numpr = cpf1->PosRuleSet[index].PosRuleCount;
+
+ for ( k = 0; k < numpr; k++ )
+ {
+ if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
+ goto next_posrule;
+
+ if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
+ goto next_posrule; /* context is too long */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
+ goto next_posrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
+ goto next_posrule;
+ }
+
+ return Do_ContextPos( gpi, pr[k].GlyphCount,
+ pr[k].PosCount, pr[k].PosLookupRecord,
+ buffer,
+ nesting_level );
+
+ next_posrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ContextPos2( GPOS_Instance* gpi,
+ HB_ContextPosFormat2* cpf2,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort i, j, k, known_classes;
+
+ HB_UShort* classes;
+ HB_UShort* cl;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_PosClassSet* pcs;
+ HB_PosClassRule* pr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ /* Note: The coverage table in format 2 doesn't give an index into
+ anything. It just lets us know whether or not we need to
+ do any lookup at all. */
+
+ error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if (cpf2->MaxContextLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
+ return error;
+
+ error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
+ &classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+ known_classes = 0;
+
+ pcs = &cpf2->PosClassSet[classes[0]];
+ if ( !pcs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End;
+ }
+
+ for ( k = 0; k < pcs->PosClassRuleCount; k++ )
+ {
+ pr = &pcs->PosClassRule[k];
+
+ if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
+ goto next_posclassrule;
+
+ if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
+ goto next_posclassrule; /* context is too long */
+
+ cl = pr->Class;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+
+ if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
+ goto next_posclassrule;
+ j++;
+ }
+
+ if ( i > known_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+ known_classes = i;
+ }
+
+ if ( cl[i - 1] != classes[i] )
+ goto next_posclassrule;
+ }
+
+ error = Do_ContextPos( gpi, pr->GlyphCount,
+ pr->PosCount, pr->PosLookupRecord,
+ buffer,
+ nesting_level );
+ goto End;
+
+ next_posclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End:
+ FREE( classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ContextPos3( GPOS_Instance* gpi,
+ HB_ContextPosFormat3* cpf3,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, i, j, property;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_Coverage* c;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
+ return HB_Err_Not_Covered;
+
+ if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
+ return HB_Err_Not_Covered; /* context is too long */
+
+ c = cpf3->Coverage;
+
+ for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextPos( gpi, cpf3->GlyphCount,
+ cpf3->PosCount, cpf3->PosLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ContextPos( GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ContextPos* cp = &st->context;
+
+ switch ( cp->PosFormat )
+ {
+ case 1:
+ return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
+ flags, context_length, nesting_level );
+
+ case 2:
+ return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
+ flags, context_length, nesting_level );
+
+ case 3:
+ return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
+ flags, context_length, nesting_level );
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+/* LookupType 8 */
+
+/* ChainPosRule */
+
+static HB_Error Load_ChainPosRule( HB_ChainPosRule* cpr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+
+ HB_PosLookupRecord* plr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cpr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpr->Backtrack = NULL;
+
+ count = cpr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = cpr->Backtrack;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail4;
+
+ for ( n = 0; n < count; n++ )
+ b[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ cpr->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpr->Input = NULL;
+
+ count = cpr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = cpr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail3;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ cpr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpr->Lookahead = NULL;
+
+ count = cpr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = cpr->Lookahead;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ l[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ cpr->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpr->PosLookupRecord = NULL;
+
+ count = cpr->PosCount;
+
+ if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = cpr->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainPosRule( HB_ChainPosRule* cpr )
+{
+ FREE( cpr->PosLookupRecord );
+ FREE( cpr->Lookahead );
+ FREE( cpr->Input );
+ FREE( cpr->Backtrack );
+}
+
+
+/* ChainPosRuleSet */
+
+static HB_Error Load_ChainPosRuleSet( HB_ChainPosRuleSet* cprs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainPosRule* cpr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cprs->ChainPosRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cprs->ChainPosRule = NULL;
+
+ if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
+ return error;
+
+ cpr = cprs->ChainPosRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainPosRule( &cpr[m] );
+
+ FREE( cpr );
+ return error;
+}
+
+
+static void Free_ChainPosRuleSet( HB_ChainPosRuleSet* cprs )
+{
+ HB_UShort n, count;
+
+ HB_ChainPosRule* cpr;
+
+
+ if ( cprs->ChainPosRule )
+ {
+ count = cprs->ChainPosRuleCount;
+ cpr = cprs->ChainPosRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosRule( &cpr[n] );
+
+ FREE( cpr );
+ }
+}
+
+
+/* ChainContextPosFormat1 */
+
+static HB_Error Load_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainPosRuleSet* cprs;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ccpf1->ChainPosRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccpf1->ChainPosRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
+ goto Fail2;
+
+ cprs = ccpf1->ChainPosRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainPosRuleSet( &cprs[m] );
+
+ FREE( cprs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextPos1( HB_ChainContextPosFormat1* ccpf1 )
+{
+ HB_UShort n, count;
+
+ HB_ChainPosRuleSet* cprs;
+
+
+ if ( ccpf1->ChainPosRuleSet )
+ {
+ count = ccpf1->ChainPosRuleSetCount;
+ cprs = ccpf1->ChainPosRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosRuleSet( &cprs[n] );
+
+ FREE( cprs );
+ }
+
+ _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
+}
+
+
+/* ChainPosClassRule */
+
+static HB_Error Load_ChainPosClassRule(
+ HB_ChainContextPosFormat2* ccpf2,
+ HB_ChainPosClassRule* cpcr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+ HB_PosLookupRecord* plr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cpcr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
+ ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
+
+ cpcr->Backtrack = NULL;
+
+ count = cpcr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = cpcr->Backtrack;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail4;
+
+ for ( n = 0; n < count; n++ )
+ b[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ cpcr->InputGlyphCount = GET_UShort();
+
+ if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
+ ccpf2->MaxInputLength = cpcr->InputGlyphCount;
+
+ FORGET_Frame();
+
+ cpcr->Input = NULL;
+
+ count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = cpcr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail3;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ cpcr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
+ ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
+
+ cpcr->Lookahead = NULL;
+
+ count = cpcr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = cpcr->Lookahead;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ l[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ cpcr->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpcr->PosLookupRecord = NULL;
+
+ count = cpcr->PosCount;
+
+ if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = cpcr->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainPosClassRule( HB_ChainPosClassRule* cpcr )
+{
+ FREE( cpcr->PosLookupRecord );
+ FREE( cpcr->Lookahead );
+ FREE( cpcr->Input );
+ FREE( cpcr->Backtrack );
+}
+
+
+/* PosClassSet */
+
+static HB_Error Load_ChainPosClassSet(
+ HB_ChainContextPosFormat2* ccpf2,
+ HB_ChainPosClassSet* cpcs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainPosClassRule* cpcr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cpcs->ChainPosClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cpcs->ChainPosClassRule = NULL;
+
+ if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
+ HB_ChainPosClassRule ) )
+ return error;
+
+ cpcr = cpcs->ChainPosClassRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainPosClassRule( &cpcr[m] );
+
+ FREE( cpcr );
+ return error;
+}
+
+
+static void Free_ChainPosClassSet( HB_ChainPosClassSet* cpcs )
+{
+ HB_UShort n, count;
+
+ HB_ChainPosClassRule* cpcr;
+
+
+ if ( cpcs->ChainPosClassRule )
+ {
+ count = cpcs->ChainPosClassRuleCount;
+ cpcr = cpcs->ChainPosClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosClassRule( &cpcr[n] );
+
+ FREE( cpcr );
+ }
+}
+
+
+/* ChainContextPosFormat2 */
+
+static HB_Error Load_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+ HB_UInt backtrack_offset, input_offset, lookahead_offset;
+
+ HB_ChainPosClassSet* cpcs;
+
+
+ base_offset = FILE_Pos() - 2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Fail5;
+
+ backtrack_offset = GET_UShort();
+ input_offset = GET_UShort();
+ lookahead_offset = GET_UShort();
+
+ /* `ChainPosClassSetCount' is the upper limit for input class values,
+ thus we read it now to make an additional safety check. No limit
+ is known or needed for the other two class definitions */
+
+ count = ccpf2->ChainPosClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
+ backtrack_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail5;
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
+ input_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
+ lookahead_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+
+ ccpf2->ChainPosClassSet = NULL;
+ ccpf2->MaxBacktrackLength = 0;
+ ccpf2->MaxInputLength = 0;
+ ccpf2->MaxLookaheadLength = 0;
+
+ if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
+ goto Fail2;
+
+ cpcs = ccpf2->ChainPosClassSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if ( new_offset != base_offset ) /* not a NULL offset */
+ {
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a ChainPosClassSet table with no entries */
+
+ ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
+ ccpf2->ChainPosClassSet[n].ChainPosClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainPosClassSet( &cpcs[m] );
+
+ FREE( cpcs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
+
+Fail3:
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
+
+Fail4:
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
+
+Fail5:
+ _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextPos2( HB_ChainContextPosFormat2* ccpf2 )
+{
+ HB_UShort n, count;
+
+ HB_ChainPosClassSet* cpcs;
+
+
+ if ( ccpf2->ChainPosClassSet )
+ {
+ count = ccpf2->ChainPosClassSetCount;
+ cpcs = ccpf2->ChainPosClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainPosClassSet( &cpcs[n] );
+
+ FREE( cpcs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
+
+ _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
+}
+
+
+/* ChainContextPosFormat3 */
+
+static HB_Error Load_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, nb, ni, nl, m, count;
+ HB_UShort backtrack_count, input_count, lookahead_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* b;
+ HB_Coverage* i;
+ HB_Coverage* l;
+ HB_PosLookupRecord* plr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccpf3->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccpf3->BacktrackCoverage = NULL;
+
+ backtrack_count = ccpf3->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
+ HB_Coverage ) )
+ return error;
+
+ b = ccpf3->BacktrackCoverage;
+
+ for ( nb = 0; nb < backtrack_count; nb++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ ccpf3->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccpf3->InputCoverage = NULL;
+
+ input_count = ccpf3->InputGlyphCount;
+
+ if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
+ goto Fail4;
+
+ i = ccpf3->InputCoverage;
+
+ for ( ni = 0; ni < input_count; ni++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ ccpf3->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccpf3->LookaheadCoverage = NULL;
+
+ lookahead_count = ccpf3->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
+ HB_Coverage ) )
+ goto Fail3;
+
+ l = ccpf3->LookaheadCoverage;
+
+ for ( nl = 0; nl < lookahead_count; nl++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ ccpf3->PosCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccpf3->PosLookupRecord = NULL;
+
+ count = ccpf3->PosCount;
+
+ if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
+ goto Fail2;
+
+ plr = ccpf3->PosLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ plr[n].SequenceIndex = GET_UShort();
+ plr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( plr );
+
+Fail2:
+ for ( m = 0; m < nl; m++ )
+ _HB_OPEN_Free_Coverage( &l[m] );
+
+ FREE( l );
+
+Fail3:
+ for ( m = 0; m < ni; m++ )
+ _HB_OPEN_Free_Coverage( &i[m] );
+
+ FREE( i );
+
+Fail4:
+ for ( m = 0; m < nb; m++ )
+ _HB_OPEN_Free_Coverage( &b[m] );
+
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainContextPos3( HB_ChainContextPosFormat3* ccpf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( ccpf3->PosLookupRecord );
+
+ if ( ccpf3->LookaheadCoverage )
+ {
+ count = ccpf3->LookaheadGlyphCount;
+ c = ccpf3->LookaheadCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccpf3->InputCoverage )
+ {
+ count = ccpf3->InputGlyphCount;
+ c = ccpf3->InputCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccpf3->BacktrackCoverage )
+ {
+ count = ccpf3->BacktrackGlyphCount;
+ c = ccpf3->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ChainContextPos */
+
+static HB_Error Load_ChainContextPos( HB_GPOS_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ChainContextPos* ccp = &st->chain;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccp->PosFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( ccp->PosFormat )
+ {
+ case 1:
+ return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
+
+ case 2:
+ return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
+
+ case 3:
+ return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ChainContextPos( HB_GPOS_SubTable* st )
+{
+ HB_ChainContextPos* ccp = &st->chain;
+
+ switch ( ccp->PosFormat )
+ {
+ case 1: Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
+ case 2: Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
+ case 3: Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ChainContextPos1(
+ GPOS_Instance* gpi,
+ HB_ChainContextPosFormat1* ccpf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, num_cpr;
+ HB_UShort bgc, igc, lgc;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_ChainPosRule* cpr;
+ HB_ChainPosRule curr_cpr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ cpr = ccpf1->ChainPosRuleSet[index].ChainPosRule;
+ num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
+
+ for ( k = 0; k < num_cpr; k++ )
+ {
+ curr_cpr = cpr[k];
+ bgc = curr_cpr.BacktrackGlyphCount;
+ igc = curr_cpr.InputGlyphCount;
+ lgc = curr_cpr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainposrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainposrule;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array */
+
+ for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainposrule;
+ j--;
+ }
+
+ /* In OpenType 1.3, it is undefined whether the offsets of
+ backtrack glyphs is in logical order or not. Version 1.4
+ will clarify this:
+
+ Logical order - a b c d e f g h i j
+ i
+ Input offsets - 0 1
+ Backtrack offsets - 3 2 1 0
+ Lookahead offsets - 0 1 2 3 */
+
+ if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
+ goto next_chainposrule;
+ }
+ }
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ goto next_chainposrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
+ goto next_chainposrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ goto next_chainposrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
+ goto next_chainposrule;
+ }
+
+ return Do_ContextPos( gpi, igc,
+ curr_cpr.PosCount,
+ curr_cpr.PosLookupRecord,
+ buffer,
+ nesting_level );
+
+ next_chainposrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ChainContextPos2(
+ GPOS_Instance* gpi,
+ HB_ChainContextPosFormat2* ccpf2,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort i, j, k;
+ HB_UShort bgc, igc, lgc;
+ HB_UShort known_backtrack_classes,
+ known_input_classes,
+ known_lookahead_classes;
+
+ HB_UShort* backtrack_classes;
+ HB_UShort* input_classes;
+ HB_UShort* lookahead_classes;
+
+ HB_UShort* bc;
+ HB_UShort* ic;
+ HB_UShort* lc;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_ChainPosClassSet* cpcs;
+ HB_ChainPosClassRule cpcr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ /* Note: The coverage table in format 2 doesn't give an index into
+ anything. It just lets us know whether or not we need to
+ do any lookup at all. */
+
+ error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
+ return error;
+ known_backtrack_classes = 0;
+
+ if (ccpf2->MaxInputLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
+ goto End3;
+ known_input_classes = 1;
+
+ if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
+ goto End2;
+ known_lookahead_classes = 0;
+
+ error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
+ &input_classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
+ if ( !cpcs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End1;
+ }
+
+ for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
+ {
+ cpcr = cpcs->ChainPosClassRule[k];
+ bgc = cpcr.BacktrackGlyphCount;
+ igc = cpcr.InputGlyphCount;
+ lgc = cpcr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainposclassrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainposclassrule;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array.
+ Note that `known_backtrack_classes' starts at index 0. */
+
+ bc = cpcr.Backtrack;
+
+ for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainposclassrule;
+ j++;
+ }
+
+ if ( i >= known_backtrack_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
+ &backtrack_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_backtrack_classes = i;
+ }
+
+ if ( bc[i] != backtrack_classes[i] )
+ goto next_chainposclassrule;
+ }
+ }
+
+ ic = cpcr.Input;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ goto next_chainposclassrule;
+ j++;
+ }
+
+ if ( i >= known_input_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
+ &input_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_input_classes = i;
+ }
+
+ if ( ic[i - 1] != input_classes[i] )
+ goto next_chainposclassrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ lc = cpcr.Lookahead;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ goto next_chainposclassrule;
+ j++;
+ }
+
+ if ( i >= known_lookahead_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
+ &lookahead_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_lookahead_classes = i;
+ }
+
+ if ( lc[i] != lookahead_classes[i] )
+ goto next_chainposclassrule;
+ }
+
+ error = Do_ContextPos( gpi, igc,
+ cpcr.PosCount,
+ cpcr.PosLookupRecord,
+ buffer,
+ nesting_level );
+ goto End1;
+
+ next_chainposclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End1:
+ FREE( lookahead_classes );
+
+End2:
+ FREE( input_classes );
+
+End3:
+ FREE( backtrack_classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ChainContextPos3(
+ GPOS_Instance* gpi,
+ HB_ChainContextPosFormat3* ccpf3,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, i, j, property;
+ HB_UShort bgc, igc, lgc;
+ HB_Error error;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_Coverage* bc;
+ HB_Coverage* ic;
+ HB_Coverage* lc;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gpos->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ bgc = ccpf3->BacktrackGlyphCount;
+ igc = ccpf3->InputGlyphCount;
+ lgc = ccpf3->LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ return HB_Err_Not_Covered;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ return HB_Err_Not_Covered;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array */
+
+ bc = ccpf3->BacktrackCoverage;
+
+ for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ return HB_Err_Not_Covered;
+ j--;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ ic = ccpf3->InputCoverage;
+
+ for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
+ {
+ /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
+ while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ lc = ccpf3->LookaheadCoverage;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextPos( gpi, igc,
+ ccpf3->PosCount,
+ ccpf3->PosLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ChainContextPos(
+ GPOS_Instance* gpi,
+ HB_GPOS_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ChainContextPos* ccp = &st->chain;
+
+ switch ( ccp->PosFormat )
+ {
+ case 1:
+ return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
+ flags, context_length,
+ nesting_level );
+
+ case 2:
+ return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
+ flags, context_length,
+ nesting_level );
+
+ case 3:
+ return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
+ flags, context_length,
+ nesting_level );
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+
+/***********
+ * GPOS API
+ ***********/
+
+
+
+HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
+ HB_UInt script_tag,
+ HB_UShort* script_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gpos || !script_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ if ( script_tag == sr[n].ScriptTag )
+ {
+ *script_index = n;
+
+ return HB_Err_Ok;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+
+HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
+ HB_UInt language_tag,
+ HB_UShort script_index,
+ HB_UShort* language_index,
+ HB_UShort* req_feature_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+
+
+ if ( !gpos || !language_index || !req_feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < s->LangSysCount; n++ )
+ if ( language_tag == lsr[n].LangSysTag )
+ {
+ *language_index = n;
+ *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
+
+ return HB_Err_Ok;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+ default language (DefaultLangSys) */
+
+
+HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
+ HB_UInt feature_tag,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UShort* feature_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+ HB_LangSys* ls;
+ HB_UShort* fi;
+
+ HB_FeatureList* fl;
+ HB_FeatureRecord* fr;
+
+
+ if ( !gpos || !feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gpos->FeatureList;
+ fr = fl->FeatureRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( language_index == 0xFFFF )
+ ls = &s->DefaultLangSys;
+ else
+ {
+ if ( language_index >= s->LangSysCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ ls = &lsr[language_index].LangSys;
+ }
+
+ fi = ls->FeatureIndex;
+
+ for ( n = 0; n < ls->FeatureCount; n++ )
+ {
+ if ( fi[n] >= fl->FeatureCount )
+ return ERR(HB_Err_Invalid_SubTable_Format);
+
+ if ( feature_tag == fr[fi[n]].FeatureTag )
+ {
+ *feature_index = fi[n];
+
+ return HB_Err_Ok;
+ }
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* The next three functions return a null-terminated list */
+
+
+HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
+ HB_UInt** script_tag_list )
+{
+ HB_Error error;
+ HB_UShort n;
+ HB_UInt* stl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gpos || !script_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ stl[n] = sr[n].ScriptTag;
+ stl[n] = 0;
+
+ *script_tag_list = stl;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list )
+{
+ HB_Error error;
+ HB_UShort n;
+ HB_UInt* ltl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+
+
+ if ( !gpos || !language_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < s->LangSysCount; n++ )
+ ltl[n] = lsr[n].LangSysTag;
+ ltl[n] = 0;
+
+ *language_tag_list = ltl;
+
+ return HB_Err_Ok;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+ default language (DefaultLangSys) */
+
+
+HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* ftl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+ HB_LangSys* ls;
+ HB_UShort* fi;
+
+ HB_FeatureList* fl;
+ HB_FeatureRecord* fr;
+
+
+ if ( !gpos || !feature_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gpos->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gpos->FeatureList;
+ fr = fl->FeatureRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( language_index == 0xFFFF )
+ ls = &s->DefaultLangSys;
+ else
+ {
+ if ( language_index >= s->LangSysCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ ls = &lsr[language_index].LangSys;
+ }
+
+ fi = ls->FeatureIndex;
+
+ if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < ls->FeatureCount; n++ )
+ {
+ if ( fi[n] >= fl->FeatureCount )
+ {
+ FREE( ftl );
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+ ftl[n] = fr[fi[n]].FeatureTag;
+ }
+ ftl[n] = 0;
+
+ *feature_tag_list = ftl;
+
+ return HB_Err_Ok;
+}
+
+
+/* Do an individual subtable lookup. Returns HB_Err_Ok if positioning
+ has been done, or HB_Err_Not_Covered if not. */
+static HB_Error GPOS_Do_Glyph_Lookup( GPOS_Instance* gpi,
+ HB_UShort lookup_index,
+ HB_Buffer buffer,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error = HB_Err_Not_Covered;
+ HB_UShort i, flags, lookup_count;
+ HB_GPOSHeader* gpos = gpi->gpos;
+ HB_Lookup* lo;
+ int lookup_type;
+
+
+ nesting_level++;
+
+ if ( nesting_level > HB_MAX_NESTING_LEVEL )
+ return ERR(HB_Err_Not_Covered); /* ERR() call intended */
+
+ lookup_count = gpos->LookupList.LookupCount;
+ if (lookup_index >= lookup_count)
+ return error;
+
+ lo = &gpos->LookupList.Lookup[lookup_index];
+ flags = lo->LookupFlag;
+ lookup_type = lo->LookupType;
+
+ for ( i = 0; i < lo->SubTableCount; i++ )
+ {
+ HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
+
+ switch (lookup_type) {
+ case HB_GPOS_LOOKUP_SINGLE:
+ error = Lookup_SinglePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_PAIR:
+ error = Lookup_PairPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_CURSIVE:
+ error = Lookup_CursivePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_MARKBASE:
+ error = Lookup_MarkBasePos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_MARKLIG:
+ error = Lookup_MarkLigPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_MARKMARK:
+ error = Lookup_MarkMarkPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_CONTEXT:
+ error = Lookup_ContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GPOS_LOOKUP_CHAIN:
+ error = Lookup_ChainContextPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;
+ /*case HB_GPOS_LOOKUP_EXTENSION:
+ error = Lookup_ExtensionPos ( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
+ default:
+ error = HB_Err_Not_Covered;
+ }
+
+ /* Check whether we have a successful positioning or an error other
+ than HB_Err_Not_Covered */
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
+ HB_Stream stream,
+ HB_UShort lookup_type )
+{
+ switch ( lookup_type ) {
+ case HB_GPOS_LOOKUP_SINGLE: return Load_SinglePos ( st, stream );
+ case HB_GPOS_LOOKUP_PAIR: return Load_PairPos ( st, stream );
+ case HB_GPOS_LOOKUP_CURSIVE: return Load_CursivePos ( st, stream );
+ case HB_GPOS_LOOKUP_MARKBASE: return Load_MarkBasePos ( st, stream );
+ case HB_GPOS_LOOKUP_MARKLIG: return Load_MarkLigPos ( st, stream );
+ case HB_GPOS_LOOKUP_MARKMARK: return Load_MarkMarkPos ( st, stream );
+ case HB_GPOS_LOOKUP_CONTEXT: return Load_ContextPos ( st, stream );
+ case HB_GPOS_LOOKUP_CHAIN: return Load_ChainContextPos ( st, stream );
+ /*case HB_GPOS_LOOKUP_EXTENSION: return Load_ExtensionPos ( st, stream );*/
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+}
+
+
+HB_INTERNAL void
+_HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
+ HB_UShort lookup_type )
+{
+ switch ( lookup_type ) {
+ case HB_GPOS_LOOKUP_SINGLE: Free_SinglePos ( st ); return;
+ case HB_GPOS_LOOKUP_PAIR: Free_PairPos ( st ); return;
+ case HB_GPOS_LOOKUP_CURSIVE: Free_CursivePos ( st ); return;
+ case HB_GPOS_LOOKUP_MARKBASE: Free_MarkBasePos ( st ); return;
+ case HB_GPOS_LOOKUP_MARKLIG: Free_MarkLigPos ( st ); return;
+ case HB_GPOS_LOOKUP_MARKMARK: Free_MarkMarkPos ( st ); return;
+ case HB_GPOS_LOOKUP_CONTEXT: Free_ContextPos ( st ); return;
+ case HB_GPOS_LOOKUP_CHAIN: Free_ChainContextPos ( st ); return;
+ /*case HB_GPOS_LOOKUP_EXTENSION: Free_ExtensionPos ( st ); return;*/
+ default: return;
+ }
+}
+
+
+/* apply one lookup to the input string object */
+
+static HB_Error GPOS_Do_String_Lookup( GPOS_Instance* gpi,
+ HB_UShort lookup_index,
+ HB_Buffer buffer )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+ HB_GPOSHeader* gpos = gpi->gpos;
+
+ HB_UInt* properties = gpos->LookupList.Properties;
+
+ const int nesting_level = 0;
+ /* 0xFFFF indicates that we don't have a context length yet */
+ const HB_UShort context_length = 0xFFFF;
+
+
+ gpi->last = 0xFFFF; /* no last valid glyph for cursive pos. */
+
+ buffer->in_pos = 0;
+ while ( buffer->in_pos < buffer->in_length )
+ {
+ if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+ {
+ /* Note that the connection between mark and base glyphs hold
+ exactly one (string) lookup. For example, it would be possible
+ that in the first lookup, mark glyph X is attached to base
+ glyph A, and in the next lookup it is attached to base glyph B.
+ It is up to the font designer to provide meaningful lookups and
+ lookup order. */
+
+ error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ {
+ /* Contrary to properties defined in GDEF, user-defined properties
+ will always stop a possible cursive positioning. */
+ gpi->last = 0xFFFF;
+
+ error = HB_Err_Not_Covered;
+ }
+
+ if ( error == HB_Err_Not_Covered )
+ (buffer->in_pos)++;
+ else
+ retError = error;
+ }
+
+ return retError;
+}
+
+
+static HB_Error Position_CursiveChain ( HB_Buffer buffer )
+{
+ HB_UInt i, j;
+ HB_Position positions = buffer->positions;
+
+ /* First handle all left-to-right connections */
+ for (j = 0; j < buffer->in_length; j++)
+ {
+ if (positions[j].cursive_chain > 0)
+ positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
+ }
+
+ /* Then handle all right-to-left connections */
+ for (i = buffer->in_length; i > 0; i--)
+ {
+ j = i - 1;
+
+ if (positions[j].cursive_chain < 0)
+ positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
+ HB_UShort feature_index,
+ HB_UInt property )
+{
+ HB_UShort i;
+
+ HB_Feature feature;
+ HB_UInt* properties;
+ HB_UShort* index;
+ HB_UShort lookup_count;
+
+ /* Each feature can only be added once */
+
+ if ( !gpos ||
+ feature_index >= gpos->FeatureList.FeatureCount ||
+ gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
+
+ properties = gpos->LookupList.Properties;
+
+ feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
+ index = feature.LookupListIndex;
+ lookup_count = gpos->LookupList.LookupCount;
+
+ for ( i = 0; i < feature.LookupListCount; i++ )
+ {
+ HB_UShort lookup_index = index[i];
+ if (lookup_index < lookup_count)
+ properties[lookup_index] |= property;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos )
+{
+ HB_UShort i;
+
+ HB_UInt* properties;
+
+
+ if ( !gpos )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gpos->FeatureList.ApplyCount = 0;
+
+ properties = gpos->LookupList.Properties;
+
+ for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
+ properties[i] = 0;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
+ HB_MMFunction mmfunc,
+ void* data )
+{
+ if ( !gpos )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gpos->mmfunc = mmfunc;
+ gpos->data = data;
+
+ return HB_Err_Ok;
+}
+
+/* If `dvi' is TRUE, glyph contour points for anchor points and device
+ tables are ignored -- you will get device independent values. */
+
+
+HB_Error HB_GPOS_Apply_String( HB_Font font,
+ HB_GPOSHeader* gpos,
+ HB_UShort load_flags,
+ HB_Buffer buffer,
+ HB_Bool dvi,
+ HB_Bool r2l )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+ GPOS_Instance gpi;
+ int i, j, lookup_count, num_features;
+
+ if ( !font || !gpos || !buffer )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( buffer->in_length == 0 )
+ return HB_Err_Not_Covered;
+
+ gpi.font = font;
+ gpi.gpos = gpos;
+ gpi.load_flags = load_flags;
+ gpi.r2l = r2l;
+ gpi.dvi = dvi;
+
+ lookup_count = gpos->LookupList.LookupCount;
+ num_features = gpos->FeatureList.ApplyCount;
+
+ if ( num_features )
+ {
+ error = _hb_buffer_clear_positions( buffer );
+ if ( error )
+ return error;
+ }
+
+ for ( i = 0; i < num_features; i++ )
+ {
+ HB_UShort feature_index = gpos->FeatureList.ApplyOrder[i];
+ HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
+
+ for ( j = 0; j < feature.LookupListCount; j++ )
+ {
+ HB_UShort lookup_index = feature.LookupListIndex[j];
+
+ /* Skip nonexistant lookups */
+ if (lookup_index >= lookup_count)
+ continue;
+
+ error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ }
+
+ if ( num_features )
+ {
+ error = Position_CursiveChain ( buffer );
+ if ( error )
+ return error;
+ }
+
+ return retError;
+}
+
+/* END */
diff --git a/third_party/harfbuzz/src/harfbuzz-gpos.h b/third_party/harfbuzz/src/harfbuzz-gpos.h
new file mode 100644
index 0000000..2840dae
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gpos.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GPOS_H
+#define HARFBUZZ_GPOS_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+
+/* Lookup types for glyph positioning */
+
+#define HB_GPOS_LOOKUP_SINGLE 1
+#define HB_GPOS_LOOKUP_PAIR 2
+#define HB_GPOS_LOOKUP_CURSIVE 3
+#define HB_GPOS_LOOKUP_MARKBASE 4
+#define HB_GPOS_LOOKUP_MARKLIG 5
+#define HB_GPOS_LOOKUP_MARKMARK 6
+#define HB_GPOS_LOOKUP_CONTEXT 7
+#define HB_GPOS_LOOKUP_CHAIN 8
+#define HB_GPOS_LOOKUP_EXTENSION 9
+
+/* A pointer to a function which accesses the PostScript interpreter.
+ Multiple Master fonts need this interface to convert a metric ID
+ (as stored in an OpenType font version 1.2 or higher) `metric_id'
+ into a metric value (returned in `metric_value').
+
+ `data' points to the user-defined structure specified during a
+ call to HB_GPOS_Register_MM_Function().
+
+ `metric_value' must be returned as a scaled value (but shouldn't
+ be rounded). */
+
+typedef HB_Error (*HB_MMFunction)(HB_Font font,
+ HB_UShort metric_id,
+ HB_Fixed* metric_value,
+ void* data );
+
+
+struct HB_GPOSHeader_
+{
+ HB_16Dot16 Version;
+
+ HB_ScriptList ScriptList;
+ HB_FeatureList FeatureList;
+ HB_LookupList LookupList;
+
+ HB_GDEFHeader* gdef;
+
+ /* this is OpenType 1.2 -- Multiple Master fonts need this
+ callback function to get various metric values from the
+ PostScript interpreter. */
+
+ HB_MMFunction mmfunc;
+ void* data;
+};
+
+typedef struct HB_GPOSHeader_ HB_GPOSHeader;
+typedef HB_GPOSHeader* HB_GPOS;
+
+
+HB_Error HB_Load_GPOS_Table( HB_Stream stream,
+ HB_GPOSHeader** gpos,
+ HB_GDEFHeader* gdef,
+ HB_Stream gdefStream );
+
+
+HB_Error HB_Done_GPOS_Table( HB_GPOSHeader* gpos );
+
+
+HB_Error HB_GPOS_Select_Script( HB_GPOSHeader* gpos,
+ HB_UInt script_tag,
+ HB_UShort* script_index );
+
+HB_Error HB_GPOS_Select_Language( HB_GPOSHeader* gpos,
+ HB_UInt language_tag,
+ HB_UShort script_index,
+ HB_UShort* language_index,
+ HB_UShort* req_feature_index );
+
+HB_Error HB_GPOS_Select_Feature( HB_GPOSHeader* gpos,
+ HB_UInt feature_tag,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UShort* feature_index );
+
+
+HB_Error HB_GPOS_Query_Scripts( HB_GPOSHeader* gpos,
+ HB_UInt** script_tag_list );
+
+HB_Error HB_GPOS_Query_Languages( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list );
+
+HB_Error HB_GPOS_Query_Features( HB_GPOSHeader* gpos,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list );
+
+
+HB_Error HB_GPOS_Add_Feature( HB_GPOSHeader* gpos,
+ HB_UShort feature_index,
+ HB_UInt property );
+
+HB_Error HB_GPOS_Clear_Features( HB_GPOSHeader* gpos );
+
+
+HB_Error HB_GPOS_Register_MM_Function( HB_GPOSHeader* gpos,
+ HB_MMFunction mmfunc,
+ void* data );
+
+/* If `dvi' is TRUE, glyph contour points for anchor points and device
+ tables are ignored -- you will get device independent values. */
+
+
+HB_Error HB_GPOS_Apply_String( HB_Font font,
+ HB_GPOSHeader* gpos,
+ HB_UShort load_flags,
+ HB_Buffer buffer,
+ HB_Bool dvi,
+ HB_Bool r2l );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GPOS_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-gsub-private.h b/third_party/harfbuzz/src/harfbuzz-gsub-private.h
new file mode 100644
index 0000000..dd5ffdf
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gsub-private.h
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GSUB_PRIVATE_H
+#define HARFBUZZ_GSUB_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-stream-private.h"
+#include "harfbuzz-gsub.h"
+
+HB_BEGIN_HEADER
+
+
+typedef union HB_GSUB_SubTable_ HB_GSUB_SubTable;
+
+/* LookupType 1 */
+
+struct HB_SingleSubstFormat1_
+{
+ HB_Short DeltaGlyphID; /* constant added to get
+ substitution glyph index */
+};
+
+typedef struct HB_SingleSubstFormat1_ HB_SingleSubstFormat1;
+
+
+struct HB_SingleSubstFormat2_
+{
+ HB_UShort GlyphCount; /* number of glyph IDs in
+ Substitute array */
+ HB_UShort* Substitute; /* array of substitute glyph IDs */
+};
+
+typedef struct HB_SingleSubstFormat2_ HB_SingleSubstFormat2;
+
+
+struct HB_SingleSubst_
+{
+ HB_UShort SubstFormat; /* 1 or 2 */
+ HB_Coverage Coverage; /* Coverage table */
+
+ union
+ {
+ HB_SingleSubstFormat1 ssf1;
+ HB_SingleSubstFormat2 ssf2;
+ } ssf;
+};
+
+typedef struct HB_SingleSubst_ HB_SingleSubst;
+
+
+/* LookupType 2 */
+
+struct HB_Sequence_
+{
+ HB_UShort GlyphCount; /* number of glyph IDs in the
+ Substitute array */
+ HB_UShort* Substitute; /* string of glyph IDs to
+ substitute */
+};
+
+typedef struct HB_Sequence_ HB_Sequence;
+
+
+struct HB_MultipleSubst_
+{
+ HB_UShort SubstFormat; /* always 1 */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort SequenceCount; /* number of Sequence tables */
+ HB_Sequence* Sequence; /* array of Sequence tables */
+};
+
+typedef struct HB_MultipleSubst_ HB_MultipleSubst;
+
+
+/* LookupType 3 */
+
+struct HB_AlternateSet_
+{
+ HB_UShort GlyphCount; /* number of glyph IDs in the
+ Alternate array */
+ HB_UShort* Alternate; /* array of alternate glyph IDs */
+};
+
+typedef struct HB_AlternateSet_ HB_AlternateSet;
+
+
+struct HB_AlternateSubst_
+{
+ HB_UShort SubstFormat; /* always 1 */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort AlternateSetCount;
+ /* number of AlternateSet tables */
+ HB_AlternateSet* AlternateSet; /* array of AlternateSet tables */
+};
+
+typedef struct HB_AlternateSubst_ HB_AlternateSubst;
+
+
+/* LookupType 4 */
+
+struct HB_Ligature_
+{
+ HB_UShort LigGlyph; /* glyphID of ligature
+ to substitute */
+ HB_UShort ComponentCount; /* number of components in ligature */
+ HB_UShort* Component; /* array of component glyph IDs */
+};
+
+typedef struct HB_Ligature_ HB_Ligature;
+
+
+struct HB_LigatureSet_
+{
+ HB_UShort LigatureCount; /* number of Ligature tables */
+ HB_Ligature* Ligature; /* array of Ligature tables */
+};
+
+typedef struct HB_LigatureSet_ HB_LigatureSet;
+
+
+struct HB_LigatureSubst_
+{
+ HB_UShort SubstFormat; /* always 1 */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort LigatureSetCount; /* number of LigatureSet tables */
+ HB_LigatureSet* LigatureSet; /* array of LigatureSet tables */
+};
+
+typedef struct HB_LigatureSubst_ HB_LigatureSubst;
+
+
+/* needed by both lookup type 5 and 6 */
+
+struct HB_SubstLookupRecord_
+{
+ HB_UShort SequenceIndex; /* index into current
+ glyph sequence */
+ HB_UShort LookupListIndex; /* Lookup to apply to that pos. */
+};
+
+typedef struct HB_SubstLookupRecord_ HB_SubstLookupRecord;
+
+
+/* LookupType 5 */
+
+struct HB_SubRule_
+{
+ HB_UShort GlyphCount; /* total number of input glyphs */
+ HB_UShort SubstCount; /* number of SubstLookupRecord
+ tables */
+ HB_UShort* Input; /* array of input glyph IDs */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecord
+ tables */
+};
+
+typedef struct HB_SubRule_ HB_SubRule;
+
+
+struct HB_SubRuleSet_
+{
+ HB_UShort SubRuleCount; /* number of SubRule tables */
+ HB_SubRule* SubRule; /* array of SubRule tables */
+};
+
+typedef struct HB_SubRuleSet_ HB_SubRuleSet;
+
+
+struct HB_ContextSubstFormat1_
+{
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort SubRuleSetCount; /* number of SubRuleSet tables */
+ HB_SubRuleSet* SubRuleSet; /* array of SubRuleSet tables */
+};
+
+typedef struct HB_ContextSubstFormat1_ HB_ContextSubstFormat1;
+
+
+struct HB_SubClassRule_
+{
+ HB_UShort GlyphCount; /* total number of context classes */
+ HB_UShort SubstCount; /* number of SubstLookupRecord
+ tables */
+ HB_UShort* Class; /* array of classes */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecord
+ tables */
+};
+
+typedef struct HB_SubClassRule_ HB_SubClassRule;
+
+
+struct HB_SubClassSet_
+{
+ HB_UShort SubClassRuleCount;
+ /* number of SubClassRule tables */
+ HB_SubClassRule* SubClassRule; /* array of SubClassRule tables */
+};
+
+typedef struct HB_SubClassSet_ HB_SubClassSet;
+
+
+/* The `MaxContextLength' field is not defined in the TTO specification
+ but simplifies the implementation of this format. It holds the
+ maximal context length used in the context rules. */
+
+struct HB_ContextSubstFormat2_
+{
+ HB_UShort MaxContextLength;
+ /* maximal context length */
+ HB_Coverage Coverage; /* Coverage table */
+ HB_ClassDefinition ClassDef; /* ClassDef table */
+ HB_UShort SubClassSetCount;
+ /* number of SubClassSet tables */
+ HB_SubClassSet* SubClassSet; /* array of SubClassSet tables */
+};
+
+typedef struct HB_ContextSubstFormat2_ HB_ContextSubstFormat2;
+
+
+struct HB_ContextSubstFormat3_
+{
+ HB_UShort GlyphCount; /* number of input glyphs */
+ HB_UShort SubstCount; /* number of SubstLookupRecords */
+ HB_Coverage* Coverage; /* array of Coverage tables */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of substitution lookups */
+};
+
+typedef struct HB_ContextSubstFormat3_ HB_ContextSubstFormat3;
+
+
+struct HB_ContextSubst_
+{
+ HB_UShort SubstFormat; /* 1, 2, or 3 */
+
+ union
+ {
+ HB_ContextSubstFormat1 csf1;
+ HB_ContextSubstFormat2 csf2;
+ HB_ContextSubstFormat3 csf3;
+ } csf;
+};
+
+typedef struct HB_ContextSubst_ HB_ContextSubst;
+
+
+/* LookupType 6 */
+
+struct HB_ChainSubRule_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* total number of backtrack glyphs */
+ HB_UShort* Backtrack; /* array of backtrack glyph IDs */
+ HB_UShort InputGlyphCount;
+ /* total number of input glyphs */
+ HB_UShort* Input; /* array of input glyph IDs */
+ HB_UShort LookaheadGlyphCount;
+ /* total number of lookahead glyphs */
+ HB_UShort* Lookahead; /* array of lookahead glyph IDs */
+ HB_UShort SubstCount; /* number of SubstLookupRecords */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of SubstLookupRecords */
+};
+
+typedef struct HB_ChainSubRule_ HB_ChainSubRule;
+
+
+struct HB_ChainSubRuleSet_
+{
+ HB_UShort ChainSubRuleCount;
+ /* number of ChainSubRule tables */
+ HB_ChainSubRule* ChainSubRule; /* array of ChainSubRule tables */
+};
+
+typedef struct HB_ChainSubRuleSet_ HB_ChainSubRuleSet;
+
+
+struct HB_ChainContextSubstFormat1_
+{
+ HB_Coverage Coverage; /* Coverage table */
+ HB_UShort ChainSubRuleSetCount;
+ /* number of ChainSubRuleSet tables */
+ HB_ChainSubRuleSet* ChainSubRuleSet;
+ /* array of ChainSubRuleSet tables */
+};
+
+typedef struct HB_ChainContextSubstFormat1_ HB_ChainContextSubstFormat1;
+
+
+struct HB_ChainSubClassRule_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* total number of backtrack
+ classes */
+ HB_UShort* Backtrack; /* array of backtrack classes */
+ HB_UShort InputGlyphCount;
+ /* total number of context classes */
+ HB_UShort* Input; /* array of context classes */
+ HB_UShort LookaheadGlyphCount;
+ /* total number of lookahead
+ classes */
+ HB_UShort* Lookahead; /* array of lookahead classes */
+ HB_UShort SubstCount; /* number of SubstLookupRecords */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of substitution lookups */
+};
+
+typedef struct HB_ChainSubClassRule_ HB_ChainSubClassRule;
+
+
+struct HB_ChainSubClassSet_
+{
+ HB_UShort ChainSubClassRuleCount;
+ /* number of ChainSubClassRule
+ tables */
+ HB_ChainSubClassRule* ChainSubClassRule;
+ /* array of ChainSubClassRule
+ tables */
+};
+
+typedef struct HB_ChainSubClassSet_ HB_ChainSubClassSet;
+
+
+/* The `MaxXXXLength' fields are not defined in the TTO specification
+ but simplifies the implementation of this format. It holds the
+ maximal context length used in the specific context rules. */
+
+struct HB_ChainContextSubstFormat2_
+{
+ HB_Coverage Coverage; /* Coverage table */
+
+ HB_UShort MaxBacktrackLength;
+ /* maximal backtrack length */
+ HB_ClassDefinition BacktrackClassDef;
+ /* BacktrackClassDef table */
+ HB_UShort MaxInputLength;
+ /* maximal input length */
+ HB_ClassDefinition InputClassDef;
+ /* InputClassDef table */
+ HB_UShort MaxLookaheadLength;
+ /* maximal lookahead length */
+ HB_ClassDefinition LookaheadClassDef;
+ /* LookaheadClassDef table */
+
+ HB_UShort ChainSubClassSetCount;
+ /* number of ChainSubClassSet
+ tables */
+ HB_ChainSubClassSet* ChainSubClassSet;
+ /* array of ChainSubClassSet
+ tables */
+};
+
+typedef struct HB_ChainContextSubstFormat2_ HB_ChainContextSubstFormat2;
+
+
+struct HB_ChainContextSubstFormat3_
+{
+ HB_UShort BacktrackGlyphCount;
+ /* number of backtrack glyphs */
+ HB_Coverage* BacktrackCoverage;
+ /* array of backtrack Coverage
+ tables */
+ HB_UShort InputGlyphCount;
+ /* number of input glyphs */
+ HB_Coverage* InputCoverage;
+ /* array of input coverage
+ tables */
+ HB_UShort LookaheadGlyphCount;
+ /* number of lookahead glyphs */
+ HB_Coverage* LookaheadCoverage;
+ /* array of lookahead coverage
+ tables */
+ HB_UShort SubstCount; /* number of SubstLookupRecords */
+ HB_SubstLookupRecord* SubstLookupRecord;
+ /* array of substitution lookups */
+};
+
+typedef struct HB_ChainContextSubstFormat3_ HB_ChainContextSubstFormat3;
+
+
+struct HB_ChainContextSubst_
+{
+ HB_UShort SubstFormat; /* 1, 2, or 3 */
+
+ union
+ {
+ HB_ChainContextSubstFormat1 ccsf1;
+ HB_ChainContextSubstFormat2 ccsf2;
+ HB_ChainContextSubstFormat3 ccsf3;
+ } ccsf;
+};
+
+typedef struct HB_ChainContextSubst_ HB_ChainContextSubst;
+
+
+#if 0
+/* LookupType 7 */
+struct HB_ExtensionSubst_
+{
+ HB_UShort SubstFormat; /* always 1 */
+ HB_UShort LookuptType; /* lookup-type of referenced subtable */
+ HB_GSUB_SubTable *subtable; /* referenced subtable */
+};
+
+typedef struct HB_ExtensionSubst_ HB_ExtensionSubst;
+#endif
+
+
+/* LookupType 8 */
+struct HB_ReverseChainContextSubst_
+{
+ HB_UShort SubstFormat; /* always 1 */
+ HB_Coverage Coverage; /* coverage table for input glyphs */
+ HB_UShort BacktrackGlyphCount; /* number of backtrack glyphs */
+ HB_Coverage* BacktrackCoverage; /* array of backtrack Coverage
+ tables */
+ HB_UShort LookaheadGlyphCount; /* number of lookahead glyphs */
+ HB_Coverage* LookaheadCoverage; /* array of lookahead Coverage
+ tables */
+ HB_UShort GlyphCount; /* number of Glyph IDs */
+ HB_UShort* Substitute; /* array of substitute Glyph ID */
+};
+
+typedef struct HB_ReverseChainContextSubst_ HB_ReverseChainContextSubst;
+
+
+union HB_GSUB_SubTable_
+{
+ HB_SingleSubst single;
+ HB_MultipleSubst multiple;
+ HB_AlternateSubst alternate;
+ HB_LigatureSubst ligature;
+ HB_ContextSubst context;
+ HB_ChainContextSubst chain;
+ HB_ReverseChainContextSubst reverse;
+};
+
+
+
+
+HB_INTERNAL HB_Error
+_HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
+ HB_Stream stream,
+ HB_UShort lookup_type );
+
+HB_INTERNAL void
+_HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
+ HB_UShort lookup_type );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GSUB_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-gsub.c b/third_party/harfbuzz/src/harfbuzz-gsub.c
new file mode 100644
index 0000000..21fec51
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gsub.c
@@ -0,0 +1,4329 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-open-private.h"
+#include "harfbuzz-gdef-private.h"
+
+static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
+ HB_UShort lookup_index,
+ HB_Buffer buffer,
+ HB_UShort context_length,
+ int nesting_level );
+
+
+
+/**********************
+ * Auxiliary functions
+ **********************/
+
+
+
+HB_Error HB_Load_GSUB_Table( HB_Stream stream,
+ HB_GSUBHeader** retptr,
+ HB_GDEFHeader* gdef,
+ HB_Stream gdefStream )
+{
+ HB_Error error;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_GSUBHeader* gsub;
+
+ if ( !retptr )
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( GOTO_Table( TTAG_GSUB ) )
+ return error;
+
+ base_offset = FILE_Pos();
+
+ if ( ALLOC ( gsub, sizeof( *gsub ) ) )
+ return error;
+
+
+ /* skip version */
+
+ if ( FILE_Seek( base_offset + 4L ) ||
+ ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList,
+ stream, HB_Type_GSUB ) ) != HB_Err_Ok )
+ goto Fail2;
+
+ gsub->gdef = gdef; /* can be NULL */
+
+ if ( ( error = _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
+ gsub->LookupList.Lookup,
+ gsub->LookupList.LookupCount ) ) )
+ goto Fail1;
+
+ *retptr = gsub;
+
+ return HB_Err_Ok;
+
+Fail1:
+ _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
+
+Fail2:
+ _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
+
+Fail3:
+ _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
+
+Fail4:
+ FREE ( gsub );
+
+
+ return error;
+}
+
+
+HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
+{
+ _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
+ _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
+ _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
+
+ FREE( gsub );
+
+ return HB_Err_Ok;
+}
+
+/*****************************
+ * SubTable related functions
+ *****************************/
+
+
+/* LookupType 1 */
+
+/* SingleSubstFormat1 */
+/* SingleSubstFormat2 */
+
+static HB_Error Load_SingleSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_SingleSubst* ss = &st->single;
+
+ HB_UShort n, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_UShort* s;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ss->SubstFormat = GET_UShort();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
+
+ FORGET_Frame();
+
+ break;
+
+ case 2:
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ss->ssf.ssf2.GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ss->ssf.ssf2.Substitute = NULL;
+
+ if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
+ goto Fail2;
+
+ s = ss->ssf.ssf2.Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ s[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( s );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ss->Coverage );
+ return error;
+}
+
+
+static void Free_SingleSubst( HB_GSUB_SubTable* st )
+{
+ HB_SingleSubst* ss = &st->single;
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ break;
+
+ case 2:
+ FREE( ss->ssf.ssf2.Substitute );
+ break;
+
+ default:
+ break;
+ }
+
+ _HB_OPEN_Free_Coverage( &ss->Coverage );
+}
+
+
+static HB_Error Lookup_SingleSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, value, property;
+ HB_Error error;
+ HB_SingleSubst* ss = &st->single;
+ HB_GDEFHeader* gdef = gsub->gdef;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ switch ( ss->SubstFormat )
+ {
+ case 1:
+ value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+ break;
+
+ case 2:
+ if ( index >= ss->ssf.ssf2.GlyphCount )
+ return ERR(HB_Err_Invalid_SubTable);
+ value = ss->ssf.ssf2.Substitute[index];
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+ break;
+
+ default:
+ return ERR(HB_Err_Invalid_SubTable);
+ }
+
+ if ( gdef && gdef->NewGlyphClasses )
+ {
+ /* we inherit the old glyph class to the substituted glyph */
+
+ error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 2 */
+
+/* Sequence */
+
+static HB_Error Load_Sequence( HB_Sequence* s,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* sub;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = s->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ s->Substitute = NULL;
+
+ if ( count )
+ {
+ if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
+ return error;
+
+ sub = s->Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( sub );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ sub[n] = GET_UShort();
+
+ FORGET_Frame();
+ }
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Sequence( HB_Sequence* s )
+{
+ FREE( s->Substitute );
+}
+
+
+/* MultipleSubstFormat1 */
+
+static HB_Error Load_MultipleSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_MultipleSubst* ms = &st->multiple;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Sequence* s;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ms->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ms->SequenceCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ms->Sequence = NULL;
+
+ if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
+ goto Fail2;
+
+ s = ms->Sequence;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_Sequence( &s[m] );
+
+ FREE( s );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ms->Coverage );
+ return error;
+}
+
+
+static void Free_MultipleSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_MultipleSubst* ms = &st->multiple;
+
+ HB_Sequence* s;
+
+
+ if ( ms->Sequence )
+ {
+ count = ms->SequenceCount;
+ s = ms->Sequence;
+
+ for ( n = 0; n < count; n++ )
+ Free_Sequence( &s[n] );
+
+ FREE( s );
+ }
+
+ _HB_OPEN_Free_Coverage( &ms->Coverage );
+}
+
+
+static HB_Error Lookup_MultipleSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, property, n, count;
+ HB_UShort*s;
+ HB_MultipleSubst* ms = &st->multiple;
+ HB_GDEFHeader* gdef = gsub->gdef;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( index >= ms->SequenceCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ count = ms->Sequence[index].GlyphCount;
+ s = ms->Sequence[index].Substitute;
+
+ if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
+ return error;
+
+ if ( gdef && gdef->NewGlyphClasses )
+ {
+ /* this is a guess only ... */
+
+ if ( property == HB_GDEF_LIGATURE )
+ property = HB_GDEF_BASE_GLYPH;
+
+ for ( n = 0; n < count; n++ )
+ {
+ error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ }
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 3 */
+
+/* AlternateSet */
+
+static HB_Error Load_AlternateSet( HB_AlternateSet* as,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* a;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = as->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ as->Alternate = NULL;
+
+ if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
+ return error;
+
+ a = as->Alternate;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( a );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ a[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_AlternateSet( HB_AlternateSet* as )
+{
+ FREE( as->Alternate );
+}
+
+
+/* AlternateSubstFormat1 */
+
+static HB_Error Load_AlternateSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_AlternateSubst* as = &st->alternate;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_AlternateSet* aset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ as->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = as->AlternateSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ as->AlternateSet = NULL;
+
+ if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
+ goto Fail2;
+
+ aset = as->AlternateSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_AlternateSet( &aset[m] );
+
+ FREE( aset );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &as->Coverage );
+ return error;
+}
+
+
+static void Free_AlternateSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_AlternateSubst* as = &st->alternate;
+
+ HB_AlternateSet* aset;
+
+
+ if ( as->AlternateSet )
+ {
+ count = as->AlternateSetCount;
+ aset = as->AlternateSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_AlternateSet( &aset[n] );
+
+ FREE( aset );
+ }
+
+ _HB_OPEN_Free_Coverage( &as->Coverage );
+}
+
+
+static HB_Error Lookup_AlternateSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, value, alt_index, property;
+ HB_AlternateSubst* as = &st->alternate;
+ HB_GDEFHeader* gdef = gsub->gdef;
+ HB_AlternateSet aset;
+
+ HB_UNUSED(nesting_level);
+
+ if ( context_length != 0xFFFF && context_length < 1 )
+ return HB_Err_Not_Covered;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ aset = as->AlternateSet[index];
+
+ /* we use a user-defined callback function to get the alternate index */
+
+ if ( gsub->altfunc )
+ alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
+ aset.GlyphCount, aset.Alternate,
+ gsub->data );
+ else
+ alt_index = 0;
+
+ value = aset.Alternate[alt_index];
+ if ( REPLACE_Glyph( buffer, value, nesting_level ) )
+ return error;
+
+ if ( gdef && gdef->NewGlyphClasses )
+ {
+ /* we inherit the old glyph class to the substituted glyph */
+
+ error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 4 */
+
+/* Ligature */
+
+static HB_Error Load_Ligature( HB_Ligature* l,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* c;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ l->LigGlyph = GET_UShort();
+ l->ComponentCount = GET_UShort();
+
+ FORGET_Frame();
+
+ l->Component = NULL;
+
+ count = l->ComponentCount - 1; /* only ComponentCount - 1 elements */
+
+ if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
+ return error;
+
+ c = l->Component;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( c );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ c[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Ligature( HB_Ligature* l )
+{
+ FREE( l->Component );
+}
+
+
+/* LigatureSet */
+
+static HB_Error Load_LigatureSet( HB_LigatureSet* ls,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Ligature* l;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ls->LigatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->Ligature = NULL;
+
+ if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
+ return error;
+
+ l = ls->Ligature;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_Ligature( &l[m] );
+
+ FREE( l );
+ return error;
+}
+
+
+static void Free_LigatureSet( HB_LigatureSet* ls )
+{
+ HB_UShort n, count;
+
+ HB_Ligature* l;
+
+
+ if ( ls->Ligature )
+ {
+ count = ls->LigatureCount;
+ l = ls->Ligature;
+
+ for ( n = 0; n < count; n++ )
+ Free_Ligature( &l[n] );
+
+ FREE( l );
+ }
+}
+
+
+/* LigatureSubstFormat1 */
+
+static HB_Error Load_LigatureSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_LigatureSubst* ls = &st->ligature;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LigatureSet* lset;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ ls->SubstFormat = GET_UShort(); /* should be 1 */
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ls->LigatureSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->LigatureSet = NULL;
+
+ if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
+ goto Fail2;
+
+ lset = ls->LigatureSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_LigatureSet( &lset[m] );
+
+ FREE( lset );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ls->Coverage );
+ return error;
+}
+
+
+static void Free_LigatureSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_LigatureSubst* ls = &st->ligature;
+
+ HB_LigatureSet* lset;
+
+
+ if ( ls->LigatureSet )
+ {
+ count = ls->LigatureSetCount;
+ lset = ls->LigatureSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_LigatureSet( &lset[n] );
+
+ FREE( lset );
+ }
+
+ _HB_OPEN_Free_Coverage( &ls->Coverage );
+}
+
+
+static HB_Error Lookup_LigatureSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort numlig, i, j, is_mark, first_is_mark = FALSE;
+ HB_UShort* c;
+ HB_LigatureSubst* ls = &st->ligature;
+ HB_GDEFHeader* gdef = gsub->gdef;
+
+ HB_Ligature* lig;
+
+ HB_UNUSED(nesting_level);
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
+ first_is_mark = TRUE;
+
+ error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( index >= ls->LigatureSetCount )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ lig = ls->LigatureSet[index].Ligature;
+
+ for ( numlig = ls->LigatureSet[index].LigatureCount;
+ numlig;
+ numlig--, lig++ )
+ {
+ if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
+ goto next_ligature; /* Not enough glyphs in input */
+
+ c = lig->Component;
+
+ is_mark = first_is_mark;
+
+ if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
+ break;
+
+ for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
+ goto next_ligature;
+ j++;
+ }
+
+ if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
+ is_mark = FALSE;
+
+ if ( IN_GLYPH( j ) != c[i - 1] )
+ goto next_ligature;
+ }
+
+ if ( gdef && gdef->NewGlyphClasses )
+ {
+ /* this is just a guess ... */
+
+ error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
+ is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+ }
+
+ if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
+ {
+ /* We don't use a new ligature ID if there are no skipped
+ glyphs and the ligature already has an ID. */
+
+ if ( IN_LIGID( buffer->in_pos ) )
+ {
+ if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
+ 0xFFFF, 0xFFFF ) )
+ return error;
+ }
+ else
+ {
+ HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
+ if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
+ 0xFFFF, ligID ) )
+ return error;
+ }
+ }
+ else
+ {
+ HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
+ if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
+ return error;
+
+ /* Now we must do a second loop to copy the skipped glyphs to
+ `out' and assign component values to it. We start with the
+ glyph after the first component. Glyphs between component
+ i and i+1 belong to component i. Together with the ligID
+ value it is later possible to check whether a specific
+ component value really belongs to a given ligature. */
+
+ for ( i = 0; i < lig->ComponentCount - 1; i++ )
+ {
+ while ( CHECK_Property( gdef, IN_CURITEM(),
+ flags, &property ) )
+ if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
+ return error;
+
+ (buffer->in_pos)++;
+ }
+ }
+
+ return HB_Err_Ok;
+
+ next_ligature:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* Do the actual substitution for a context substitution (either format
+ 5 or 6). This is only called after we've determined that the input
+ matches the subrule. */
+
+static HB_Error Do_ContextSubst( HB_GSUBHeader* gsub,
+ HB_UShort GlyphCount,
+ HB_UShort SubstCount,
+ HB_SubstLookupRecord* subst,
+ HB_Buffer buffer,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UInt i, old_pos;
+
+
+ i = 0;
+
+ while ( i < GlyphCount )
+ {
+ if ( SubstCount && i == subst->SequenceIndex )
+ {
+ old_pos = buffer->in_pos;
+
+ /* Do a substitution */
+
+ error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
+ GlyphCount, nesting_level );
+
+ subst++;
+ SubstCount--;
+ i += buffer->in_pos - old_pos;
+
+ if ( error == HB_Err_Not_Covered )
+ {
+ if ( COPY_Glyph( buffer ) )
+ return error;
+ i++;
+ }
+ else if ( error )
+ return error;
+ }
+ else
+ {
+ /* No substitution for this index */
+
+ if ( COPY_Glyph( buffer ) )
+ return error;
+ i++;
+ }
+ }
+
+ return HB_Err_Ok;
+}
+
+
+/* LookupType 5 */
+
+/* SubRule */
+
+static HB_Error Load_SubRule( HB_SubRule* sr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* i;
+
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ sr->GlyphCount = GET_UShort();
+ sr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ sr->Input = NULL;
+
+ count = sr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
+ return error;
+
+ i = sr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ sr->SubstLookupRecord = NULL;
+
+ count = sr->SubstCount;
+
+ if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = sr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( i );
+ return error;
+}
+
+
+static void Free_SubRule( HB_SubRule* sr )
+{
+ FREE( sr->SubstLookupRecord );
+ FREE( sr->Input );
+}
+
+
+/* SubRuleSet */
+
+static HB_Error Load_SubRuleSet( HB_SubRuleSet* srs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubRule* sr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = srs->SubRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ srs->SubRule = NULL;
+
+ if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
+ return error;
+
+ sr = srs->SubRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubRule( &sr[m] );
+
+ FREE( sr );
+ return error;
+}
+
+
+static void Free_SubRuleSet( HB_SubRuleSet* srs )
+{
+ HB_UShort n, count;
+
+ HB_SubRule* sr;
+
+
+ if ( srs->SubRule )
+ {
+ count = srs->SubRuleCount;
+ sr = srs->SubRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubRule( &sr[n] );
+
+ FREE( sr );
+ }
+}
+
+
+/* ContextSubstFormat1 */
+
+static HB_Error Load_ContextSubst1( HB_ContextSubstFormat1* csf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubRuleSet* srs;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = csf1->SubRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csf1->SubRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
+ goto Fail2;
+
+ srs = csf1->SubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_SubRuleSet( &srs[m] );
+
+ FREE( srs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &csf1->Coverage );
+ return error;
+}
+
+
+static void Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
+{
+ HB_UShort n, count;
+
+ HB_SubRuleSet* srs;
+
+
+ if ( csf1->SubRuleSet )
+ {
+ count = csf1->SubRuleSetCount;
+ srs = csf1->SubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubRuleSet( &srs[n] );
+
+ FREE( srs );
+ }
+
+ _HB_OPEN_Free_Coverage( &csf1->Coverage );
+}
+
+
+/* SubClassRule */
+
+static HB_Error Load_SubClassRule( HB_ContextSubstFormat2* csf2,
+ HB_SubClassRule* scr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* c;
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ scr->GlyphCount = GET_UShort();
+ scr->SubstCount = GET_UShort();
+
+ if ( scr->GlyphCount > csf2->MaxContextLength )
+ csf2->MaxContextLength = scr->GlyphCount;
+
+ FORGET_Frame();
+
+ scr->Class = NULL;
+
+ count = scr->GlyphCount - 1; /* only GlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
+ return error;
+
+ c = scr->Class;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ c[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ scr->SubstLookupRecord = NULL;
+
+ count = scr->SubstCount;
+
+ if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = scr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( c );
+ return error;
+}
+
+
+static void Free_SubClassRule( HB_SubClassRule* scr )
+{
+ FREE( scr->SubstLookupRecord );
+ FREE( scr->Class );
+}
+
+
+/* SubClassSet */
+
+static HB_Error Load_SubClassSet( HB_ContextSubstFormat2* csf2,
+ HB_SubClassSet* scs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubClassRule* scr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = scs->SubClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ scs->SubClassRule = NULL;
+
+ if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
+ return error;
+
+ scr = scs->SubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubClassRule( csf2, &scr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubClassRule( &scr[m] );
+
+ FREE( scr );
+ return error;
+}
+
+
+static void Free_SubClassSet( HB_SubClassSet* scs )
+{
+ HB_UShort n, count;
+
+ HB_SubClassRule* scr;
+
+
+ if ( scs->SubClassRule )
+ {
+ count = scs->SubClassRuleCount;
+ scr = scs->SubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubClassRule( &scr[n] );
+
+ FREE( scr );
+ }
+}
+
+
+/* ContextSubstFormat2 */
+
+static HB_Error Load_ContextSubst2( HB_ContextSubstFormat2* csf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubClassSet* scs;
+
+
+ base_offset = FILE_Pos() - 2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 4L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ /* `SubClassSetCount' is the upper limit for class values, thus we
+ read it now to make an additional safety check. */
+
+ count = csf2->SubClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+
+ csf2->SubClassSet = NULL;
+ csf2->MaxContextLength = 0;
+
+ if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
+ goto Fail2;
+
+ scs = csf2->SubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if ( new_offset != base_offset ) /* not a NULL offset */
+ {
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubClassSet( csf2, &scs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a SubClassSet table with no entries */
+
+ csf2->SubClassSet[n].SubClassRuleCount = 0;
+ csf2->SubClassSet[n].SubClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_SubClassSet( &scs[m] );
+
+ FREE( scs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
+
+Fail3:
+ _HB_OPEN_Free_Coverage( &csf2->Coverage );
+ return error;
+}
+
+
+static void Free_ContextSubst2( HB_ContextSubstFormat2* csf2 )
+{
+ HB_UShort n, count;
+
+ HB_SubClassSet* scs;
+
+
+ if ( csf2->SubClassSet )
+ {
+ count = csf2->SubClassSetCount;
+ scs = csf2->SubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubClassSet( &scs[n] );
+
+ FREE( scs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
+ _HB_OPEN_Free_Coverage( &csf2->Coverage );
+}
+
+
+/* ContextSubstFormat3 */
+
+static HB_Error Load_ContextSubst3( HB_ContextSubstFormat3* csf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* c;
+ HB_SubstLookupRecord* slr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ csf3->GlyphCount = GET_UShort();
+ csf3->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csf3->Coverage = NULL;
+
+ count = csf3->GlyphCount;
+
+ if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
+ return error;
+
+ c = csf3->Coverage;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ csf3->SubstLookupRecord = NULL;
+
+ count = csf3->SubstCount;
+
+ if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = csf3->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ for ( m = 0; m < n; m++ )
+ _HB_OPEN_Free_Coverage( &c[m] );
+
+ FREE( c );
+ return error;
+}
+
+
+static void Free_ContextSubst3( HB_ContextSubstFormat3* csf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( csf3->SubstLookupRecord );
+
+ if ( csf3->Coverage )
+ {
+ count = csf3->GlyphCount;
+ c = csf3->Coverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ContextSubst */
+
+static HB_Error Load_ContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ContextSubst* cs = &st->context;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: return Load_ContextSubst1( &cs->csf.csf1, stream );
+ case 2: return Load_ContextSubst2( &cs->csf.csf2, stream );
+ case 3: return Load_ContextSubst3( &cs->csf.csf3, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_ContextSubst* cs = &st->context;
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: Free_ContextSubst1( &cs->csf.csf1 ); break;
+ case 2: Free_ContextSubst2( &cs->csf.csf2 ); break;
+ case 3: Free_ContextSubst3( &cs->csf.csf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ContextSubst1( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat1* csf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, numsr;
+ HB_Error error;
+
+ HB_SubRule* sr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ sr = csf1->SubRuleSet[index].SubRule;
+ numsr = csf1->SubRuleSet[index].SubRuleCount;
+
+ for ( k = 0; k < numsr; k++ )
+ {
+ if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
+ goto next_subrule;
+
+ if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
+ goto next_subrule; /* context is too long */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
+ goto next_subrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
+ goto next_subrule;
+ }
+
+ return Do_ContextSubst( gsub, sr[k].GlyphCount,
+ sr[k].SubstCount, sr[k].SubstLookupRecord,
+ buffer,
+ nesting_level );
+ next_subrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ContextSubst2( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat2* csf2,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort i, j, k, known_classes;
+
+ HB_UShort* classes;
+ HB_UShort* cl;
+
+ HB_SubClassSet* scs;
+ HB_SubClassRule* sr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ /* Note: The coverage table in format 2 doesn't give an index into
+ anything. It just lets us know whether or not we need to
+ do any lookup at all. */
+
+ error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if (csf2->MaxContextLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
+ return error;
+
+ error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
+ &classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+ known_classes = 0;
+
+ scs = &csf2->SubClassSet[classes[0]];
+ if ( !scs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End;
+ }
+
+ for ( k = 0; k < scs->SubClassRuleCount; k++ )
+ {
+ sr = &scs->SubClassRule[k];
+
+ if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
+ goto next_subclassrule;
+
+ if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
+ goto next_subclassrule; /* context is too long */
+
+ cl = sr->Class;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+
+ if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
+ goto next_subclassrule;
+ j++;
+ }
+
+ if ( i > known_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End;
+ known_classes = i;
+ }
+
+ if ( cl[i - 1] != classes[i] )
+ goto next_subclassrule;
+ }
+
+ error = Do_ContextSubst( gsub, sr->GlyphCount,
+ sr->SubstCount, sr->SubstLookupRecord,
+ buffer,
+ nesting_level );
+ goto End;
+
+ next_subclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End:
+ FREE( classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ContextSubst3( HB_GSUBHeader* gsub,
+ HB_ContextSubstFormat3* csf3,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error;
+ HB_UShort index, i, j, property;
+
+ HB_Coverage* c;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
+ return HB_Err_Not_Covered;
+
+ if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
+ return HB_Err_Not_Covered; /* context is too long */
+
+ c = csf3->Coverage;
+
+ for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextSubst( gsub, csf3->GlyphCount,
+ csf3->SubstCount, csf3->SubstLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ContextSubst* cs = &st->context;
+
+ switch ( cs->SubstFormat )
+ {
+ case 1: return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
+ case 2: return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
+ case 3: return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+/* LookupType 6 */
+
+/* ChainSubRule */
+
+static HB_Error Load_ChainSubRule( HB_ChainSubRule* csr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ csr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Backtrack = NULL;
+
+ count = csr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = csr->Backtrack;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail4;
+
+ for ( n = 0; n < count; n++ )
+ b[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ csr->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Input = NULL;
+
+ count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = csr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail3;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ csr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->Lookahead = NULL;
+
+ count = csr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = csr->Lookahead;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ l[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ csr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csr->SubstLookupRecord = NULL;
+
+ count = csr->SubstCount;
+
+ if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = csr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainSubRule( HB_ChainSubRule* csr )
+{
+ FREE( csr->SubstLookupRecord );
+ FREE( csr->Lookahead );
+ FREE( csr->Input );
+ FREE( csr->Backtrack );
+}
+
+
+/* ChainSubRuleSet */
+
+static HB_Error Load_ChainSubRuleSet( HB_ChainSubRuleSet* csrs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubRule* csr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = csrs->ChainSubRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ csrs->ChainSubRule = NULL;
+
+ if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
+ return error;
+
+ csr = csrs->ChainSubRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubRule( &csr[m] );
+
+ FREE( csr );
+ return error;
+}
+
+
+static void Free_ChainSubRuleSet( HB_ChainSubRuleSet* csrs )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubRule* csr;
+
+
+ if ( csrs->ChainSubRule )
+ {
+ count = csrs->ChainSubRuleCount;
+ csr = csrs->ChainSubRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRule( &csr[n] );
+
+ FREE( csr );
+ }
+}
+
+
+/* ChainContextSubstFormat1 */
+
+static HB_Error Load_ChainContextSubst1(
+ HB_ChainContextSubstFormat1* ccsf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubRuleSet* csrs;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = ccsf1->ChainSubRuleSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf1->ChainSubRuleSet = NULL;
+
+ if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
+ goto Fail2;
+
+ csrs = ccsf1->ChainSubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubRuleSet( &csrs[m] );
+
+ FREE( csrs );
+
+Fail2:
+ _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextSubst1( HB_ChainContextSubstFormat1* ccsf1 )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubRuleSet* csrs;
+
+
+ if ( ccsf1->ChainSubRuleSet )
+ {
+ count = ccsf1->ChainSubRuleSetCount;
+ csrs = ccsf1->ChainSubRuleSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubRuleSet( &csrs[n] );
+
+ FREE( csrs );
+ }
+
+ _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
+}
+
+
+/* ChainSubClassRule */
+
+static HB_Error Load_ChainSubClassRule(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_ChainSubClassRule* cscr,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* b;
+ HB_UShort* i;
+ HB_UShort* l;
+ HB_SubstLookupRecord* slr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cscr->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
+ ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
+
+ cscr->Backtrack = NULL;
+
+ count = cscr->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
+ return error;
+
+ b = cscr->Backtrack;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail4;
+
+ for ( n = 0; n < count; n++ )
+ b[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ cscr->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
+ ccsf2->MaxInputLength = cscr->InputGlyphCount;
+
+ cscr->Input = NULL;
+
+ count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
+
+ if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
+ goto Fail4;
+
+ i = cscr->Input;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail3;
+
+ for ( n = 0; n < count; n++ )
+ i[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ cscr->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
+ ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
+
+ cscr->Lookahead = NULL;
+
+ count = cscr->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
+ goto Fail3;
+
+ l = cscr->Lookahead;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail2;
+
+ for ( n = 0; n < count; n++ )
+ l[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ cscr->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cscr->SubstLookupRecord = NULL;
+
+ count = cscr->SubstCount;
+
+ if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = cscr->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ FREE( l );
+
+Fail3:
+ FREE( i );
+
+Fail4:
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainSubClassRule( HB_ChainSubClassRule* cscr )
+{
+ FREE( cscr->SubstLookupRecord );
+ FREE( cscr->Lookahead );
+ FREE( cscr->Input );
+ FREE( cscr->Backtrack );
+}
+
+
+/* SubClassSet */
+
+static HB_Error Load_ChainSubClassSet(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_ChainSubClassSet* cscs,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ChainSubClassRule* cscr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cscs->ChainSubClassRuleCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cscs->ChainSubClassRule = NULL;
+
+ if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
+ HB_ChainSubClassRule ) )
+ return error;
+
+ cscr = cscs->ChainSubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubClassRule( &cscr[m] );
+
+ FREE( cscr );
+ return error;
+}
+
+
+static void Free_ChainSubClassSet( HB_ChainSubClassSet* cscs )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubClassRule* cscr;
+
+
+ if ( cscs->ChainSubClassRule )
+ {
+ count = cscs->ChainSubClassRuleCount;
+ cscr = cscs->ChainSubClassRule;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubClassRule( &cscr[n] );
+
+ FREE( cscr );
+ }
+}
+
+
+/* ChainContextSubstFormat2 */
+
+static HB_Error Load_ChainContextSubst2(
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n = 0, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+ HB_UInt backtrack_offset, input_offset, lookahead_offset;
+
+ HB_ChainSubClassSet* cscs;
+
+
+ base_offset = FILE_Pos() - 2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+ if ( ACCESS_Frame( 8L ) )
+ goto Fail5;
+
+ backtrack_offset = GET_UShort();
+ input_offset = GET_UShort();
+ lookahead_offset = GET_UShort();
+
+ /* `ChainSubClassSetCount' is the upper limit for input class values,
+ thus we read it now to make an additional safety check. No limit
+ is known or needed for the other two class definitions */
+
+ count = ccsf2->ChainSubClassSetCount = GET_UShort();
+
+ FORGET_Frame();
+
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
+ backtrack_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail5;
+
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
+ input_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
+ lookahead_offset, base_offset,
+ stream ) ) != HB_Err_Ok )
+ goto Fail3;
+
+ ccsf2->ChainSubClassSet = NULL;
+ ccsf2->MaxBacktrackLength = 0;
+ ccsf2->MaxInputLength = 0;
+ ccsf2->MaxLookaheadLength = 0;
+
+ if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
+ goto Fail2;
+
+ cscs = ccsf2->ChainSubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if ( new_offset != base_offset ) /* not a NULL offset */
+ {
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
+ stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a ChainSubClassSet table with no entries */
+
+ ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
+ ccsf2->ChainSubClassSet[n].ChainSubClassRule = NULL;
+ }
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_ChainSubClassSet( &cscs[m] );
+
+ FREE( cscs );
+
+Fail2:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+
+Fail3:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
+
+Fail4:
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+Fail5:
+ _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
+ return error;
+}
+
+
+static void Free_ChainContextSubst2( HB_ChainContextSubstFormat2* ccsf2 )
+{
+ HB_UShort n, count;
+
+ HB_ChainSubClassSet* cscs;
+
+
+ if ( ccsf2->ChainSubClassSet )
+ {
+ count = ccsf2->ChainSubClassSetCount;
+ cscs = ccsf2->ChainSubClassSet;
+
+ for ( n = 0; n < count; n++ )
+ Free_ChainSubClassSet( &cscs[n] );
+
+ FREE( cscs );
+ }
+
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
+ _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
+
+ _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
+}
+
+
+/* ChainContextSubstFormat3 */
+
+static HB_Error Load_ChainContextSubst3(
+ HB_ChainContextSubstFormat3* ccsf3,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, nb = 0, ni =0, nl = 0, m, count;
+ HB_UShort backtrack_count, input_count, lookahead_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* b;
+ HB_Coverage* i;
+ HB_Coverage* l;
+ HB_SubstLookupRecord* slr;
+
+
+ base_offset = FILE_Pos() - 2L;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccsf3->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->BacktrackCoverage = NULL;
+
+ backtrack_count = ccsf3->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
+ HB_Coverage ) )
+ return error;
+
+ b = ccsf3->BacktrackCoverage;
+
+ for ( nb = 0; nb < backtrack_count; nb++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
+ goto Fail4;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ ccsf3->InputGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->InputCoverage = NULL;
+
+ input_count = ccsf3->InputGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
+ goto Fail4;
+
+ i = ccsf3->InputCoverage;
+
+ for ( ni = 0; ni < input_count; ni++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ ccsf3->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->LookaheadCoverage = NULL;
+
+ lookahead_count = ccsf3->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
+ HB_Coverage ) )
+ goto Fail3;
+
+ l = ccsf3->LookaheadCoverage;
+
+ for ( nl = 0; nl < lookahead_count; nl++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ ccsf3->SubstCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ccsf3->SubstLookupRecord = NULL;
+
+ count = ccsf3->SubstCount;
+
+ if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
+ HB_SubstLookupRecord ) )
+ goto Fail2;
+
+ slr = ccsf3->SubstLookupRecord;
+
+ if ( ACCESS_Frame( count * 4L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ {
+ slr[n].SequenceIndex = GET_UShort();
+ slr[n].LookupListIndex = GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( slr );
+
+Fail2:
+ for ( m = 0; m < nl; m++ )
+ _HB_OPEN_Free_Coverage( &l[m] );
+
+ FREE( l );
+
+Fail3:
+ for ( m = 0; m < ni; m++ )
+ _HB_OPEN_Free_Coverage( &i[m] );
+
+ FREE( i );
+
+Fail4:
+ for ( m = 0; m < nb; m++ )
+ _HB_OPEN_Free_Coverage( &b[m] );
+
+ FREE( b );
+ return error;
+}
+
+
+static void Free_ChainContextSubst3( HB_ChainContextSubstFormat3* ccsf3 )
+{
+ HB_UShort n, count;
+
+ HB_Coverage* c;
+
+
+ FREE( ccsf3->SubstLookupRecord );
+
+ if ( ccsf3->LookaheadCoverage )
+ {
+ count = ccsf3->LookaheadGlyphCount;
+ c = ccsf3->LookaheadCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->InputCoverage )
+ {
+ count = ccsf3->InputGlyphCount;
+ c = ccsf3->InputCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( ccsf3->BacktrackCoverage )
+ {
+ count = ccsf3->BacktrackGlyphCount;
+ c = ccsf3->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+}
+
+
+/* ChainContextSubst */
+
+static HB_Error Load_ChainContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ ccs->SubstFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( ccs->SubstFormat ) {
+ case 1: return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
+ case 2: return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
+ case 3: return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+static void Free_ChainContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ switch ( ccs->SubstFormat ) {
+ case 1: Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
+ case 2: Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
+ case 3: Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Lookup_ChainContextSubst1( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat1* ccsf1,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_UShort i, j, k, num_csr;
+ HB_UShort bgc, igc, lgc;
+ HB_Error error;
+
+ HB_ChainSubRule* csr;
+ HB_ChainSubRule curr_csr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ csr = ccsf1->ChainSubRuleSet[index].ChainSubRule;
+ num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
+
+ for ( k = 0; k < num_csr; k++ )
+ {
+ curr_csr = csr[k];
+ bgc = curr_csr.BacktrackGlyphCount;
+ igc = curr_csr.InputGlyphCount;
+ lgc = curr_csr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainsubrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainsubrule;
+
+ if ( bgc )
+ {
+ /* since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array */
+
+ for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainsubrule;
+ j--;
+ }
+
+ /* In OpenType 1.3, it is undefined whether the offsets of
+ backtrack glyphs is in logical order or not. Version 1.4
+ will clarify this:
+
+ Logical order - a b c d e f g h i j
+ i
+ Input offsets - 0 1
+ Backtrack offsets - 3 2 1 0
+ Lookahead offsets - 0 1 2 3 */
+
+ if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
+ goto next_chainsubrule;
+ }
+ }
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ goto next_chainsubrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
+ goto next_chainsubrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ goto next_chainsubrule;
+ j++;
+ }
+
+ if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
+ goto next_chainsubrule;
+ }
+
+ return Do_ContextSubst( gsub, igc,
+ curr_csr.SubstCount,
+ curr_csr.SubstLookupRecord,
+ buffer,
+ nesting_level );
+
+ next_chainsubrule:
+ ;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Lookup_ChainContextSubst2( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat2* ccsf2,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, property;
+ HB_Error error;
+ HB_UShort i, j, k;
+ HB_UShort bgc, igc, lgc;
+ HB_UShort known_backtrack_classes,
+ known_input_classes,
+ known_lookahead_classes;
+
+ HB_UShort* backtrack_classes;
+ HB_UShort* input_classes;
+ HB_UShort* lookahead_classes;
+
+ HB_UShort* bc;
+ HB_UShort* ic;
+ HB_UShort* lc;
+
+ HB_ChainSubClassSet* cscs;
+ HB_ChainSubClassRule ccsr;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ /* Note: The coverage table in format 2 doesn't give an index into
+ anything. It just lets us know whether or not we need to
+ do any lookup at all. */
+
+ error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
+ if ( error )
+ return error;
+
+ if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
+ return error;
+ known_backtrack_classes = 0;
+
+ if (ccsf2->MaxInputLength < 1)
+ return HB_Err_Not_Covered;
+
+ if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
+ goto End3;
+ known_input_classes = 1;
+
+ if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
+ goto End2;
+ known_lookahead_classes = 0;
+
+ error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
+ &input_classes[0], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
+ if ( !cscs )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto End1;
+ }
+
+ for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
+ {
+ ccsr = cscs->ChainSubClassRule[k];
+ bgc = ccsr.BacktrackGlyphCount;
+ igc = ccsr.InputGlyphCount;
+ lgc = ccsr.LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ goto next_chainsubclassrule;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ goto next_chainsubclassrule;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array.
+ Note that `known_backtrack_classes' starts at index 0. */
+
+ bc = ccsr.Backtrack;
+
+ for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + 1 == bgc - i )
+ goto next_chainsubclassrule;
+ j--;
+ }
+
+ if ( i >= known_backtrack_classes )
+ {
+ /* Keeps us from having to do this for each rule */
+
+ error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
+ &backtrack_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_backtrack_classes = i;
+ }
+
+ if ( bc[i] != backtrack_classes[i] )
+ goto next_chainsubclassrule;
+ }
+ }
+
+ ic = ccsr.Input;
+
+ /* Start at 1 because [0] is implied */
+
+ for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ goto next_chainsubclassrule;
+ j++;
+ }
+
+ if ( i >= known_input_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
+ &input_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_input_classes = i;
+ }
+
+ if ( ic[i - 1] != input_classes[i] )
+ goto next_chainsubclassrule;
+ }
+
+ /* we are starting to check for lookahead glyphs right after the
+ last context glyph */
+
+ lc = ccsr.Lookahead;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ goto next_chainsubclassrule;
+ j++;
+ }
+
+ if ( i >= known_lookahead_classes )
+ {
+ error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
+ &lookahead_classes[i], NULL );
+ if ( error && error != HB_Err_Not_Covered )
+ goto End1;
+ known_lookahead_classes = i;
+ }
+
+ if ( lc[i] != lookahead_classes[i] )
+ goto next_chainsubclassrule;
+ }
+
+ error = Do_ContextSubst( gsub, igc,
+ ccsr.SubstCount,
+ ccsr.SubstLookupRecord,
+ buffer,
+ nesting_level );
+ goto End1;
+
+ next_chainsubclassrule:
+ ;
+ }
+
+ error = HB_Err_Not_Covered;
+
+End1:
+ FREE( lookahead_classes );
+
+End2:
+ FREE( input_classes );
+
+End3:
+ FREE( backtrack_classes );
+ return error;
+}
+
+
+static HB_Error Lookup_ChainContextSubst3( HB_GSUBHeader* gsub,
+ HB_ChainContextSubstFormat3* ccsf3,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, i, j, property;
+ HB_UShort bgc, igc, lgc;
+ HB_Error error;
+
+ HB_Coverage* bc;
+ HB_Coverage* ic;
+ HB_Coverage* lc;
+ HB_GDEFHeader* gdef;
+
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ bgc = ccsf3->BacktrackGlyphCount;
+ igc = ccsf3->InputGlyphCount;
+ lgc = ccsf3->LookaheadGlyphCount;
+
+ if ( context_length != 0xFFFF && context_length < igc )
+ return HB_Err_Not_Covered;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
+ return HB_Err_Not_Covered;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array */
+
+ bc = ccsf3->BacktrackCoverage;
+
+ for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ return HB_Err_Not_Covered;
+ j--;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ ic = ccsf3->InputCoverage;
+
+ for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
+ {
+ /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
+ while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ /* we are starting for lookahead glyphs right after the last context
+ glyph */
+
+ lc = ccsf3->LookaheadCoverage;
+
+ for ( i = 0; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ return Do_ContextSubst( gsub, igc,
+ ccsf3->SubstCount,
+ ccsf3->SubstLookupRecord,
+ buffer,
+ nesting_level );
+}
+
+
+static HB_Error Lookup_ChainContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_ChainContextSubst* ccs = &st->chain;
+
+ switch ( ccs->SubstFormat ) {
+ case 1: return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
+ case 2: return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
+ case 3: return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+}
+
+
+static HB_Error Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+
+ HB_UShort m, count;
+
+ HB_UShort nb = 0, nl = 0, n;
+ HB_UShort backtrack_count, lookahead_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Coverage* b;
+ HB_Coverage* l;
+ HB_UShort* sub;
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ rccs->SubstFormat = GET_UShort();
+
+ if ( rccs->SubstFormat != 1 )
+ return ERR(HB_Err_Invalid_SubTable_Format);
+
+ FORGET_Frame();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail4;
+
+ rccs->BacktrackGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->BacktrackCoverage = NULL;
+
+ backtrack_count = rccs->BacktrackGlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
+ HB_Coverage ) )
+ goto Fail4;
+
+ b = rccs->BacktrackCoverage;
+
+ for ( nb = 0; nb < backtrack_count; nb++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
+ goto Fail3;
+ (void)FILE_Seek( cur_offset );
+ }
+
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail3;
+
+ rccs->LookaheadGlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->LookaheadCoverage = NULL;
+
+ lookahead_count = rccs->LookaheadGlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
+ HB_Coverage ) )
+ goto Fail3;
+
+ l = rccs->LookaheadCoverage;
+
+ for ( nl = 0; nl < lookahead_count; nl++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
+ goto Fail2;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ rccs->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ rccs->Substitute = NULL;
+
+ count = rccs->GlyphCount;
+
+ if ( ALLOC_ARRAY( rccs->Substitute, count,
+ HB_UShort ) )
+ goto Fail2;
+
+ sub = rccs->Substitute;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail1;
+
+ for ( n = 0; n < count; n++ )
+ sub[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( sub );
+
+Fail2:
+ for ( m = 0; m < nl; m++ )
+ _HB_OPEN_Free_Coverage( &l[m] );
+
+ FREE( l );
+
+Fail3:
+ for ( m = 0; m < nb; m++ )
+ _HB_OPEN_Free_Coverage( &b[m] );
+
+ FREE( b );
+
+Fail4:
+ _HB_OPEN_Free_Coverage( &rccs->Coverage );
+ return error;
+}
+
+
+static void Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
+{
+ HB_UShort n, count;
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+
+ HB_Coverage* c;
+
+ _HB_OPEN_Free_Coverage( &rccs->Coverage );
+
+ if ( rccs->LookaheadCoverage )
+ {
+ count = rccs->LookaheadGlyphCount;
+ c = rccs->LookaheadCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ if ( rccs->BacktrackCoverage )
+ {
+ count = rccs->BacktrackGlyphCount;
+ c = rccs->BacktrackCoverage;
+
+ for ( n = 0; n < count; n++ )
+ _HB_OPEN_Free_Coverage( &c[n] );
+
+ FREE( c );
+ }
+
+ FREE ( rccs->Substitute );
+}
+
+
+static HB_Error Lookup_ReverseChainContextSubst( HB_GSUBHeader* gsub,
+ HB_GSUB_SubTable* st,
+ HB_Buffer buffer,
+ HB_UShort flags,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_UShort index, input_index, i, j, property;
+ HB_UShort bgc, lgc;
+ HB_Error error;
+
+ HB_ReverseChainContextSubst* rccs = &st->reverse;
+ HB_Coverage* bc;
+ HB_Coverage* lc;
+ HB_GDEFHeader* gdef;
+
+ if ( nesting_level != 1 || context_length != 0xFFFF )
+ return HB_Err_Not_Covered;
+
+ gdef = gsub->gdef;
+
+ if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
+ return error;
+
+ bgc = rccs->BacktrackGlyphCount;
+ lgc = rccs->LookaheadGlyphCount;
+
+ /* check whether context is too long; it is a first guess only */
+
+ if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
+ return HB_Err_Not_Covered;
+
+ if ( bgc )
+ {
+ /* Since we don't know in advance the number of glyphs to inspect,
+ we search backwards for matches in the backtrack glyph array */
+
+ bc = rccs->BacktrackCoverage;
+
+ for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + 1 == bgc - i )
+ return HB_Err_Not_Covered;
+ j--;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+ }
+
+ j = buffer->in_pos;
+
+ error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
+ if ( error )
+ return error;
+
+ lc = rccs->LookaheadCoverage;
+
+ for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
+ {
+ while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
+ {
+ if ( error && error != HB_Err_Not_Covered )
+ return error;
+
+ if ( j + lgc - i == (HB_Int)buffer->in_length )
+ return HB_Err_Not_Covered;
+ j++;
+ }
+
+ error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
+ if ( error )
+ return error;
+ }
+
+ IN_CURGLYPH() = rccs->Substitute[input_index];
+ buffer->in_pos--; /* Reverse! */
+
+ return error;
+}
+
+
+
+/***********
+ * GSUB API
+ ***********/
+
+
+
+HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub,
+ HB_UInt script_tag,
+ HB_UShort* script_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gsub || !script_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ if ( script_tag == sr[n].ScriptTag )
+ {
+ *script_index = n;
+
+ return HB_Err_Ok;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+
+HB_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub,
+ HB_UInt language_tag,
+ HB_UShort script_index,
+ HB_UShort* language_index,
+ HB_UShort* req_feature_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+
+
+ if ( !gsub || !language_index || !req_feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < s->LangSysCount; n++ )
+ if ( language_tag == lsr[n].LangSysTag )
+ {
+ *language_index = n;
+ *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
+
+ return HB_Err_Ok;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+ default language (DefaultLangSys) */
+
+
+HB_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub,
+ HB_UInt feature_tag,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UShort* feature_index )
+{
+ HB_UShort n;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+ HB_LangSys* ls;
+ HB_UShort* fi;
+
+ HB_FeatureList* fl;
+ HB_FeatureRecord* fr;
+
+
+ if ( !gsub || !feature_index )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gsub->FeatureList;
+ fr = fl->FeatureRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( language_index == 0xFFFF )
+ ls = &s->DefaultLangSys;
+ else
+ {
+ if ( language_index >= s->LangSysCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ ls = &lsr[language_index].LangSys;
+ }
+
+ fi = ls->FeatureIndex;
+
+ for ( n = 0; n < ls->FeatureCount; n++ )
+ {
+ if ( fi[n] >= fl->FeatureCount )
+ return ERR(HB_Err_Invalid_SubTable_Format);
+
+ if ( feature_tag == fr[fi[n]].FeatureTag )
+ {
+ *feature_index = fi[n];
+
+ return HB_Err_Ok;
+ }
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+/* The next three functions return a null-terminated list */
+
+
+HB_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub,
+ HB_UInt** script_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* stl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+
+
+ if ( !gsub || !script_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ stl[n] = sr[n].ScriptTag;
+ stl[n] = 0;
+
+ *script_tag_list = stl;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* ltl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+
+
+ if ( !gsub || !language_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < s->LangSysCount; n++ )
+ ltl[n] = lsr[n].LangSysTag;
+ ltl[n] = 0;
+
+ *language_tag_list = ltl;
+
+ return HB_Err_Ok;
+}
+
+
+/* selecting 0xFFFF for language_index asks for the values of the
+ default language (DefaultLangSys) */
+
+
+HB_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list )
+{
+ HB_UShort n;
+ HB_Error error;
+ HB_UInt* ftl;
+
+ HB_ScriptList* sl;
+ HB_ScriptRecord* sr;
+ HB_ScriptTable* s;
+ HB_LangSysRecord* lsr;
+ HB_LangSys* ls;
+ HB_UShort* fi;
+
+ HB_FeatureList* fl;
+ HB_FeatureRecord* fr;
+
+
+ if ( !gsub || !feature_tag_list )
+ return ERR(HB_Err_Invalid_Argument);
+
+ sl = &gsub->ScriptList;
+ sr = sl->ScriptRecord;
+
+ fl = &gsub->FeatureList;
+ fr = fl->FeatureRecord;
+
+ if ( script_index >= sl->ScriptCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ s = &sr[script_index].Script;
+ lsr = s->LangSysRecord;
+
+ if ( language_index == 0xFFFF )
+ ls = &s->DefaultLangSys;
+ else
+ {
+ if ( language_index >= s->LangSysCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ ls = &lsr[language_index].LangSys;
+ }
+
+ fi = ls->FeatureIndex;
+
+ if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
+ return error;
+
+ for ( n = 0; n < ls->FeatureCount; n++ )
+ {
+ if ( fi[n] >= fl->FeatureCount )
+ {
+ FREE( ftl );
+ return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+ ftl[n] = fr[fi[n]].FeatureTag;
+ }
+ ftl[n] = 0;
+
+ *feature_tag_list = ftl;
+
+ return HB_Err_Ok;
+}
+
+
+/* Do an individual subtable lookup. Returns HB_Err_Ok if substitution
+ has been done, or HB_Err_Not_Covered if not. */
+static HB_Error GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
+ HB_UShort lookup_index,
+ HB_Buffer buffer,
+ HB_UShort context_length,
+ int nesting_level )
+{
+ HB_Error error = HB_Err_Not_Covered;
+ HB_UShort i, flags, lookup_count;
+ HB_Lookup* lo;
+ int lookup_type;
+
+ nesting_level++;
+
+ if ( nesting_level > HB_MAX_NESTING_LEVEL )
+ return ERR(HB_Err_Not_Covered); /* ERR() call intended */
+
+ lookup_count = gsub->LookupList.LookupCount;
+ if (lookup_index >= lookup_count)
+ return error;
+
+ lo = &gsub->LookupList.Lookup[lookup_index];
+ flags = lo->LookupFlag;
+ lookup_type = lo->LookupType;
+
+ for ( i = 0; i < lo->SubTableCount; i++ )
+ {
+ HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
+
+ switch (lookup_type) {
+ case HB_GSUB_LOOKUP_SINGLE:
+ error = Lookup_SingleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_MULTIPLE:
+ error = Lookup_MultipleSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_ALTERNATE:
+ error = Lookup_AlternateSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_LIGATURE:
+ error = Lookup_LigatureSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_CONTEXT:
+ error = Lookup_ContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ case HB_GSUB_LOOKUP_CHAIN:
+ error = Lookup_ChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ /*case HB_GSUB_LOOKUP_EXTENSION:
+ error = Lookup_ExtensionSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN:
+ error = Lookup_ReverseChainContextSubst ( gsub, st, buffer, flags, context_length, nesting_level ); break;
+ default:
+ error = HB_Err_Not_Covered;
+ };
+
+ /* Check whether we have a successful substitution or an error other
+ than HB_Err_Not_Covered */
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+
+ return HB_Err_Not_Covered;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
+ HB_Stream stream,
+ HB_UShort lookup_type )
+{
+ switch (lookup_type) {
+ case HB_GSUB_LOOKUP_SINGLE: return Load_SingleSubst ( st, stream );
+ case HB_GSUB_LOOKUP_MULTIPLE: return Load_MultipleSubst ( st, stream );
+ case HB_GSUB_LOOKUP_ALTERNATE: return Load_AlternateSubst ( st, stream );
+ case HB_GSUB_LOOKUP_LIGATURE: return Load_LigatureSubst ( st, stream );
+ case HB_GSUB_LOOKUP_CONTEXT: return Load_ContextSubst ( st, stream );
+ case HB_GSUB_LOOKUP_CHAIN: return Load_ChainContextSubst ( st, stream );
+ /*case HB_GSUB_LOOKUP_EXTENSION: return Load_ExtensionSubst ( st, stream );*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN: return Load_ReverseChainContextSubst ( st, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ };
+}
+
+
+HB_INTERNAL void
+_HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
+ HB_UShort lookup_type )
+{
+ switch ( lookup_type ) {
+ case HB_GSUB_LOOKUP_SINGLE: Free_SingleSubst ( st ); return;
+ case HB_GSUB_LOOKUP_MULTIPLE: Free_MultipleSubst ( st ); return;
+ case HB_GSUB_LOOKUP_ALTERNATE: Free_AlternateSubst ( st ); return;
+ case HB_GSUB_LOOKUP_LIGATURE: Free_LigatureSubst ( st ); return;
+ case HB_GSUB_LOOKUP_CONTEXT: Free_ContextSubst ( st ); return;
+ case HB_GSUB_LOOKUP_CHAIN: Free_ChainContextSubst ( st ); return;
+ /*case HB_GSUB_LOOKUP_EXTENSION: Free_ExtensionSubst ( st ); return;*/
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN: Free_ReverseChainContextSubst ( st ); return;
+ default: return;
+ };
+}
+
+
+
+/* apply one lookup to the input string object */
+
+static HB_Error GSUB_Do_String_Lookup( HB_GSUBHeader* gsub,
+ HB_UShort lookup_index,
+ HB_Buffer buffer )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+
+ HB_UInt* properties = gsub->LookupList.Properties;
+ int lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
+
+ const int nesting_level = 0;
+ /* 0xFFFF indicates that we don't have a context length yet */
+ const HB_UShort context_length = 0xFFFF;
+
+ switch (lookup_type) {
+
+ case HB_GSUB_LOOKUP_SINGLE:
+ case HB_GSUB_LOOKUP_MULTIPLE:
+ case HB_GSUB_LOOKUP_ALTERNATE:
+ case HB_GSUB_LOOKUP_LIGATURE:
+ case HB_GSUB_LOOKUP_CONTEXT:
+ case HB_GSUB_LOOKUP_CHAIN:
+ /* in/out forward substitution (implemented lazy) */
+
+ _hb_buffer_clear_output ( buffer );
+ buffer->in_pos = 0;
+ while ( buffer->in_pos < buffer->in_length )
+ {
+ if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+ {
+ error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ else
+ error = HB_Err_Not_Covered;
+
+ if ( error == HB_Err_Not_Covered )
+ if ( COPY_Glyph ( buffer ) )
+ return error;
+ }
+ /* we shouldn't swap if error occurred.
+ *
+ * also don't swap if nothing changed (ie HB_Err_Not_Covered).
+ * shouldn't matter in that case though.
+ */
+ if ( retError == HB_Err_Ok )
+ _hb_buffer_swap( buffer );
+
+ return retError;
+
+ case HB_GSUB_LOOKUP_REVERSE_CHAIN:
+ /* in-place backward substitution */
+
+ buffer->in_pos = buffer->in_length - 1;
+ do
+ {
+ if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
+ {
+ error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ else
+ error = HB_Err_Not_Covered;
+
+ if ( error == HB_Err_Not_Covered )
+ buffer->in_pos--;
+ }
+ while ((HB_Int) buffer->in_pos >= 0);
+
+ return retError;
+
+ /*case HB_GSUB_LOOKUP_EXTENSION:*/
+ default:
+ return retError;
+ };
+}
+
+
+HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub,
+ HB_UShort feature_index,
+ HB_UInt property )
+{
+ HB_UShort i;
+
+ HB_Feature feature;
+ HB_UInt* properties;
+ HB_UShort* index;
+ HB_UShort lookup_count;
+
+ /* Each feature can only be added once */
+
+ if ( !gsub ||
+ feature_index >= gsub->FeatureList.FeatureCount ||
+ gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
+
+ properties = gsub->LookupList.Properties;
+
+ feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
+ index = feature.LookupListIndex;
+ lookup_count = gsub->LookupList.LookupCount;
+
+ for ( i = 0; i < feature.LookupListCount; i++ )
+ {
+ HB_UShort lookup_index = index[i];
+ if (lookup_index < lookup_count)
+ properties[lookup_index] |= property;
+ }
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub )
+{
+ HB_UShort i;
+
+ HB_UInt* properties;
+
+
+ if ( !gsub )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->FeatureList.ApplyCount = 0;
+
+ properties = gsub->LookupList.Properties;
+
+ for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
+ properties[i] = 0;
+
+ return HB_Err_Ok;
+}
+
+
+
+HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub,
+ HB_AltFunction altfunc,
+ void* data )
+{
+ if ( !gsub )
+ return ERR(HB_Err_Invalid_Argument);
+
+ gsub->altfunc = altfunc;
+ gsub->data = data;
+
+ return HB_Err_Ok;
+}
+
+/* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
+ * feature were applied, or HB_Err_Ok otherwise.
+ */
+HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub,
+ HB_Buffer buffer )
+{
+ HB_Error error, retError = HB_Err_Not_Covered;
+ int i, j, lookup_count, num_features;
+
+ if ( !gsub ||
+ !buffer)
+ return ERR(HB_Err_Invalid_Argument);
+
+ if ( buffer->in_length == 0 )
+ return retError;
+
+ lookup_count = gsub->LookupList.LookupCount;
+ num_features = gsub->FeatureList.ApplyCount;
+
+ for ( i = 0; i < num_features; i++)
+ {
+ HB_UShort feature_index = gsub->FeatureList.ApplyOrder[i];
+ HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
+
+ for ( j = 0; j < feature.LookupListCount; j++ )
+ {
+ HB_UShort lookup_index = feature.LookupListIndex[j];
+
+ /* Skip nonexistant lookups */
+ if (lookup_index >= lookup_count)
+ continue;
+
+ error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
+ if ( error )
+ {
+ if ( error != HB_Err_Not_Covered )
+ return error;
+ }
+ else
+ retError = error;
+ }
+ }
+
+ error = retError;
+
+ return error;
+}
+
+
+/* END */
diff --git a/third_party/harfbuzz/src/harfbuzz-gsub.h b/third_party/harfbuzz/src/harfbuzz-gsub.h
new file mode 100644
index 0000000..1ca3f0c
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-gsub.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_GSUB_H
+#define HARFBUZZ_GSUB_H
+
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-buffer.h"
+
+HB_BEGIN_HEADER
+
+
+/* Lookup types for glyph substitution */
+
+#define HB_GSUB_LOOKUP_SINGLE 1
+#define HB_GSUB_LOOKUP_MULTIPLE 2
+#define HB_GSUB_LOOKUP_ALTERNATE 3
+#define HB_GSUB_LOOKUP_LIGATURE 4
+#define HB_GSUB_LOOKUP_CONTEXT 5
+#define HB_GSUB_LOOKUP_CHAIN 6
+#define HB_GSUB_LOOKUP_EXTENSION 7
+#define HB_GSUB_LOOKUP_REVERSE_CHAIN 8
+
+
+/* A pointer to a function which selects the alternate glyph. `pos' is
+ the position of the glyph with index `glyphID', `num_alternates'
+ gives the number of alternates in the `alternates' array. `data'
+ points to the user-defined structure specified during a call to
+ HB_GSUB_Register_Alternate_Function(). The function must return an
+ index into the `alternates' array. */
+
+typedef HB_UShort (*HB_AltFunction)(HB_UInt pos,
+ HB_UShort glyphID,
+ HB_UShort num_alternates,
+ HB_UShort* alternates,
+ void* data );
+
+
+struct HB_GSUBHeader_
+{
+ HB_UInt offset;
+
+ HB_16Dot16 Version;
+
+ HB_ScriptList ScriptList;
+ HB_FeatureList FeatureList;
+ HB_LookupList LookupList;
+
+ HB_GDEFHeader* gdef;
+
+ /* the next two fields are used for an alternate substitution callback
+ function to select the proper alternate glyph. */
+
+ HB_AltFunction altfunc;
+ void* data;
+};
+
+typedef struct HB_GSUBHeader_ HB_GSUBHeader;
+typedef HB_GSUBHeader* HB_GSUB;
+
+
+HB_Error HB_Load_GSUB_Table( HB_Stream stream,
+ HB_GSUBHeader** gsub,
+ HB_GDEFHeader* gdef,
+ HB_Stream gdefStream );
+
+
+HB_Error HB_Done_GSUB_Table( HB_GSUBHeader* gsub );
+
+
+HB_Error HB_GSUB_Select_Script( HB_GSUBHeader* gsub,
+ HB_UInt script_tag,
+ HB_UShort* script_index );
+
+HB_Error HB_GSUB_Select_Language( HB_GSUBHeader* gsub,
+ HB_UInt language_tag,
+ HB_UShort script_index,
+ HB_UShort* language_index,
+ HB_UShort* req_feature_index );
+
+HB_Error HB_GSUB_Select_Feature( HB_GSUBHeader* gsub,
+ HB_UInt feature_tag,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UShort* feature_index );
+
+
+HB_Error HB_GSUB_Query_Scripts( HB_GSUBHeader* gsub,
+ HB_UInt** script_tag_list );
+
+HB_Error HB_GSUB_Query_Languages( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UInt** language_tag_list );
+
+HB_Error HB_GSUB_Query_Features( HB_GSUBHeader* gsub,
+ HB_UShort script_index,
+ HB_UShort language_index,
+ HB_UInt** feature_tag_list );
+
+
+HB_Error HB_GSUB_Add_Feature( HB_GSUBHeader* gsub,
+ HB_UShort feature_index,
+ HB_UInt property );
+
+HB_Error HB_GSUB_Clear_Features( HB_GSUBHeader* gsub );
+
+
+HB_Error HB_GSUB_Register_Alternate_Function( HB_GSUBHeader* gsub,
+ HB_AltFunction altfunc,
+ void* data );
+
+
+HB_Error HB_GSUB_Apply_String( HB_GSUBHeader* gsub,
+ HB_Buffer buffer );
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_GSUB_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-hangul.c b/third_party/harfbuzz/src/harfbuzz-hangul.c
new file mode 100644
index 0000000..a819dac
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-hangul.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+
+/*
+// Hangul is a syllable based script. Unicode reserves a large range
+// for precomposed hangul, where syllables are already precomposed to
+// their final glyph shape. In addition, a so called jamo range is
+// defined, that can be used to express old Hangul. Modern hangul
+// syllables can also be expressed as jamo, and should be composed
+// into syllables. The operation is rather simple and mathematical.
+
+// Every hangul jamo is classified as being either a Leading consonant
+// (L), and intermediat Vowel (V) or a trailing consonant (T). Modern
+// hangul syllables (the ones in the precomposed area can be of type
+// LV or LVT.
+//
+// Syllable breaks do _not_ occur between:
+//
+// L L, V or precomposed
+// V, LV V, T
+// LVT, T T
+//
+// A standard syllable is of the form L+V+T*. The above rules allow
+// nonstandard syllables L*V*T*. To transform them into standard
+// syllables fill characters L_f and V_f can be inserted.
+*/
+
+enum {
+ Hangul_SBase = 0xac00,
+ Hangul_LBase = 0x1100,
+ Hangul_VBase = 0x1161,
+ Hangul_TBase = 0x11a7,
+ Hangul_SCount = 11172,
+ Hangul_LCount = 19,
+ Hangul_VCount = 21,
+ Hangul_TCount = 28,
+ Hangul_NCount = 21*28
+};
+
+#define hangul_isPrecomposed(uc) \
+ (uc >= Hangul_SBase && uc < Hangul_SBase + Hangul_SCount)
+
+#define hangul_isLV(uc) \
+ ((uc - Hangul_SBase) % Hangul_TCount == 0)
+
+typedef enum {
+ L,
+ V,
+ T,
+ LV,
+ LVT,
+ X
+} HangulType;
+
+static HangulType hangul_type(unsigned short uc) {
+ if (uc > Hangul_SBase && uc < Hangul_SBase + Hangul_SCount)
+ return hangul_isLV(uc) ? LV : LVT;
+ if (uc < Hangul_LBase || uc > 0x11ff)
+ return X;
+ if (uc < Hangul_VBase)
+ return L;
+ if (uc < Hangul_TBase)
+ return V;
+ return T;
+}
+
+static int hangul_nextSyllableBoundary(const HB_UChar16 *s, int start, int end)
+{
+ const HB_UChar16 *uc = s + start;
+
+ HangulType state = hangul_type(*uc);
+ int pos = 1;
+
+ while (pos < end - start) {
+ HangulType newState = hangul_type(uc[pos]);
+ switch(newState) {
+ case X:
+ goto finish;
+ case L:
+ case V:
+ case T:
+ if (state > newState)
+ goto finish;
+ state = newState;
+ break;
+ case LV:
+ if (state > L)
+ goto finish;
+ state = V;
+ break;
+ case LVT:
+ if (state > L)
+ goto finish;
+ state = T;
+ }
+ ++pos;
+ }
+
+ finish:
+ return start+pos;
+}
+
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature hangul_features [] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('l', 'j', 'm', 'o'), CcmpProperty },
+ { HB_MAKE_TAG('j', 'j', 'm', 'o'), CcmpProperty },
+ { HB_MAKE_TAG('t', 'j', 'm', 'o'), CcmpProperty },
+ { 0, 0 }
+};
+#endif
+
+static HB_Bool hangul_shape_syllable(HB_ShaperItem *item, HB_Bool openType)
+{
+ const HB_UChar16 *ch = item->string + item->item.pos;
+ int len = item->item.length;
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+
+ int i;
+ HB_UChar16 composed = 0;
+ /* see if we can compose the syllable into a modern hangul */
+ if (item->item.length == 2) {
+ int LIndex = ch[0] - Hangul_LBase;
+ int VIndex = ch[1] - Hangul_VBase;
+ if (LIndex >= 0 && LIndex < Hangul_LCount &&
+ VIndex >= 0 && VIndex < Hangul_VCount)
+ composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + Hangul_SBase;
+ } else if (item->item.length == 3) {
+ int LIndex = ch[0] - Hangul_LBase;
+ int VIndex = ch[1] - Hangul_VBase;
+ int TIndex = ch[2] - Hangul_TBase;
+ if (LIndex >= 0 && LIndex < Hangul_LCount &&
+ VIndex >= 0 && VIndex < Hangul_VCount &&
+ TIndex >= 0 && TIndex < Hangul_TCount)
+ composed = (LIndex * Hangul_VCount + VIndex) * Hangul_TCount + TIndex + Hangul_SBase;
+ }
+
+
+
+ /* if we have a modern hangul use the composed form */
+ if (composed) {
+ ch = &composed;
+ len = 1;
+ }
+
+ if (!item->font->klass->convertStringToGlyphIndices(item->font,
+ ch, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2))
+ return FALSE;
+ for (i = 0; i < len; i++) {
+ item->attributes[i].mark = FALSE;
+ item->attributes[i].clusterStart = FALSE;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = FALSE;
+ /*IDEBUG(" %d: %4x", i, ch[i].unicode()); */
+ }
+
+#ifndef NO_OPENTYPE
+ if (!composed && openType) {
+ HB_Bool positioned;
+
+ HB_STACKARRAY(unsigned short, logClusters, len);
+ for (i = 0; i < len; ++i)
+ logClusters[i] = i;
+ item->log_clusters = logClusters;
+
+ HB_OpenTypeShape(item, /*properties*/0);
+
+ positioned = HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE);
+
+ HB_FREE_STACKARRAY(logClusters);
+
+ if (!positioned)
+ return FALSE;
+ } else {
+ HB_HeuristicPosition(item);
+ }
+#endif
+
+ item->attributes[0].clusterStart = TRUE;
+ return TRUE;
+}
+
+HB_Bool HB_HangulShape(HB_ShaperItem *item)
+{
+ const HB_UChar16 *uc = item->string + item->item.pos;
+ HB_Bool allPrecomposed = TRUE;
+ int i;
+
+ assert(item->item.script == HB_Script_Hangul);
+
+ for (i = 0; i < (int)item->item.length; ++i) {
+ if (!hangul_isPrecomposed(uc[i])) {
+ allPrecomposed = FALSE;
+ break;
+ }
+ }
+
+ if (!allPrecomposed) {
+ HB_Bool openType = FALSE;
+ unsigned short *logClusters = item->log_clusters;
+ HB_ShaperItem syllable;
+ int first_glyph = 0;
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+
+#ifndef NO_OPENTYPE
+ openType = HB_SelectScript(item, hangul_features);
+#endif
+ syllable = *item;
+
+ while (sstart < end) {
+ int send = hangul_nextSyllableBoundary(item->string, sstart, end);
+
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!hangul_shape_syllable(&syllable, openType)) {
+ item->num_glyphs += syllable.num_glyphs;
+ return FALSE;
+ }
+ /* fix logcluster array */
+ for (i = sstart; i < send; ++i)
+ logClusters[i-item->item.pos] = first_glyph;
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return TRUE;
+ }
+
+ return HB_BasicShape(item);
+}
+
+
diff --git a/third_party/harfbuzz/src/harfbuzz-hebrew.c b/third_party/harfbuzz/src/harfbuzz-hebrew.c
new file mode 100644
index 0000000..533a063
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-hebrew.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+#include <assert.h>
+
+/*
+// Uniscribe also defines dlig for Hebrew, but we leave this out for now, as it's mostly
+// ligatures one does not want in modern Hebrew (as lam-alef ligatures).
+*/
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature hebrew_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ {0, 0}
+};
+#endif
+
+/* Hebrew shaping. In the non opentype case we try to use the
+ presentation forms specified for Hebrew. Especially for the
+ ligatures with Dagesh this gives much better results than we could
+ achieve manually.
+*/
+HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item)
+{
+ enum {
+ Dagesh = 0x5bc,
+ ShinDot = 0x5c1,
+ SinDot = 0x5c2,
+ Patah = 0x5b7,
+ Qamats = 0x5b8,
+ Holam = 0x5b9,
+ Rafe = 0x5bf
+ };
+
+ assert(shaper_item->item.script == HB_Script_Hebrew);
+
+#ifndef NO_OPENTYPE
+ if (HB_SelectScript(shaper_item, hebrew_features)) {
+
+ const int availableGlyphs = shaper_item->num_glyphs;
+ if (!HB_ConvertStringToGlyphIndices(shaper_item))
+ return FALSE;
+
+
+ HB_HeuristicSetGlyphAttributes(shaper_item);
+ HB_OpenTypeShape(shaper_item, /*properties*/0);
+ return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE);
+ }
+#endif
+
+ {
+ const HB_UChar16 *uc = shaper_item->string + shaper_item->item.pos;
+ unsigned short *logClusters = shaper_item->log_clusters;
+ HB_GlyphAttributes *attributes = shaper_item->attributes;
+
+ HB_Bool haveGlyphs;
+ int slen = 1;
+ int cluster_start = 0;
+ hb_uint32 i;
+
+ HB_STACKARRAY(HB_UChar16, shapedChars, 2 * shaper_item->item.length);
+ *shapedChars = *uc;
+ logClusters[0] = 0;
+
+ for (i = 1; i < shaper_item->item.length; ++i) {
+ hb_uint16 base = shapedChars[slen-1];
+ hb_uint16 shaped = 0;
+ HB_Bool invalid = FALSE;
+ if (uc[i] == Dagesh) {
+ if (base >= 0x5d0
+ && base <= 0x5ea
+ && base != 0x5d7
+ && base != 0x5dd
+ && base != 0x5df
+ && base != 0x5e2
+ && base != 0x5e5) {
+ shaped = base - 0x5d0 + 0xfb30;
+ } else if (base == 0xfb2a || base == 0xfb2b /* Shin with Shin or Sin dot */) {
+ shaped = base + 2;
+ } else {
+ invalid = TRUE;
+ }
+ } else if (uc[i] == ShinDot) {
+ if (base == 0x05e9)
+ shaped = 0xfb2a;
+ else if (base == 0xfb49)
+ shaped = 0xfb2c;
+ else
+ invalid = TRUE;
+ } else if (uc[i] == SinDot) {
+ if (base == 0x05e9)
+ shaped = 0xfb2b;
+ else if (base == 0xfb49)
+ shaped = 0xfb2d;
+ else
+ invalid = TRUE;
+ } else if (uc[i] == Patah) {
+ if (base == 0x5d0)
+ shaped = 0xfb2e;
+ } else if (uc[i] == Qamats) {
+ if (base == 0x5d0)
+ shaped = 0xfb2f;
+ } else if (uc[i] == Holam) {
+ if (base == 0x5d5)
+ shaped = 0xfb4b;
+ } else if (uc[i] == Rafe) {
+ if (base == 0x5d1)
+ shaped = 0xfb4c;
+ else if (base == 0x5db)
+ shaped = 0xfb4d;
+ else if (base == 0x5e4)
+ shaped = 0xfb4e;
+ }
+
+ if (invalid) {
+ shapedChars[slen] = 0x25cc;
+ attributes[slen].clusterStart = TRUE;
+ attributes[slen].mark = FALSE;
+ attributes[slen].combiningClass = 0;
+ cluster_start = slen;
+ ++slen;
+ }
+ if (shaped) {
+ if (shaper_item->font->klass->canRender(shaper_item->font, (HB_UChar16 *)&shaped, 1)) {
+ shapedChars[slen-1] = shaped;
+ } else
+ shaped = 0;
+ }
+ if (!shaped) {
+ HB_CharCategory category;
+ int cmb;
+ shapedChars[slen] = uc[i];
+ HB_GetUnicodeCharProperties(uc[i], &category, &cmb);
+ if (category != HB_Mark_NonSpacing) {
+ attributes[slen].clusterStart = TRUE;
+ attributes[slen].mark = FALSE;
+ attributes[slen].combiningClass = 0;
+ attributes[slen].dontPrint = HB_IsControlChar(uc[i]);
+ cluster_start = slen;
+ } else {
+ attributes[slen].clusterStart = FALSE;
+ attributes[slen].mark = TRUE;
+ attributes[slen].combiningClass = cmb;
+ }
+ ++slen;
+ }
+ logClusters[i] = cluster_start;
+ }
+
+ haveGlyphs = shaper_item->font->klass
+ ->convertStringToGlyphIndices(shaper_item->font,
+ shapedChars, slen,
+ shaper_item->glyphs, &shaper_item->num_glyphs,
+ shaper_item->item.bidiLevel % 2);
+
+ HB_FREE_STACKARRAY(shapedChars);
+
+ if (!haveGlyphs)
+ return FALSE;
+
+ HB_HeuristicPosition(shaper_item);
+ }
+
+ return TRUE;
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-impl.c b/third_party/harfbuzz/src/harfbuzz-impl.c
new file mode 100644
index 0000000..9056a55
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-impl.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+
+
+HB_INTERNAL HB_Pointer
+_hb_alloc(size_t size,
+ HB_Error *perror )
+{
+ HB_Error error = 0;
+ HB_Pointer block = NULL;
+
+ if ( size > 0 )
+ {
+ block = calloc( 1, size );
+ if ( !block )
+ error = ERR(HB_Err_Out_Of_Memory);
+ }
+
+ *perror = error;
+ return block;
+}
+
+
+HB_INTERNAL HB_Pointer
+_hb_realloc(HB_Pointer block,
+ size_t new_size,
+ HB_Error *perror )
+{
+ HB_Pointer block2 = NULL;
+ HB_Error error = 0;
+
+ block2 = realloc( block, new_size );
+ if ( block2 == NULL && new_size != 0 )
+ error = ERR(HB_Err_Out_Of_Memory);
+
+ if ( !error )
+ block = block2;
+
+ *perror = error;
+ return block;
+}
+
+
+HB_INTERNAL void
+_hb_free( HB_Pointer block )
+{
+ if ( block )
+ free( block );
+}
+
+
+/* helper func to set a breakpoint on */
+HB_INTERNAL HB_Error
+_hb_err (HB_Error code)
+{
+ return code;
+}
diff --git a/third_party/harfbuzz/src/harfbuzz-impl.h b/third_party/harfbuzz/src/harfbuzz-impl.h
new file mode 100644
index 0000000..5f43049
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-impl.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_IMPL_H
+#define HARFBUZZ_IMPL_H
+
+#include "harfbuzz-global.h"
+
+#include <stdlib.h>
+
+HB_BEGIN_HEADER
+
+#ifndef HB_INTERNAL
+# define HB_INTERNAL
+#endif
+
+#ifndef NULL
+# define NULL ((void *)0)
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef TTAG_GDEF
+# define TTAG_GDEF HB_MAKE_TAG( 'G', 'D', 'E', 'F' )
+#endif
+#ifndef TTAG_GPOS
+# define TTAG_GPOS HB_MAKE_TAG( 'G', 'P', 'O', 'S' )
+#endif
+#ifndef TTAG_GSUB
+# define TTAG_GSUB HB_MAKE_TAG( 'G', 'S', 'U', 'B' )
+#endif
+
+#ifndef HB_UNUSED
+# define HB_UNUSED(arg) ((arg) = (arg))
+#endif
+
+#define HB_LIKELY(cond) (cond)
+#define HB_UNLIKELY(cond) (cond)
+
+#define ARRAY_LEN(Array) ((int)(sizeof (Array) / sizeof (Array)[0]))
+
+
+
+#define HB_IsHighSurrogate(ucs) \
+ (((ucs) & 0xfc00) == 0xd800)
+
+#define HB_IsLowSurrogate(ucs) \
+ (((ucs) & 0xfc00) == 0xdc00)
+
+#define HB_SurrogateToUcs4(high, low) \
+ (((HB_UChar32)(high))<<10) + (low) - 0x35fdc00;
+
+
+
+
+
+#define ALLOC(_ptr,_size) \
+ ( (_ptr) = _hb_alloc( _size, &error ), error != 0 )
+
+#define REALLOC(_ptr,_newsz) \
+ ( (_ptr) = _hb_realloc( (_ptr), (_newsz), &error ), error != 0 )
+
+#define FREE(_ptr) \
+ do { \
+ if ( (_ptr) ) \
+ { \
+ _hb_free( _ptr ); \
+ _ptr = NULL; \
+ } \
+ } while (0)
+
+#define ALLOC_ARRAY(_ptr,_count,_type) \
+ ALLOC(_ptr,(_count)*sizeof(_type))
+
+#define REALLOC_ARRAY(_ptr,_newcnt,_type) \
+ REALLOC(_ptr,(_newcnt)*sizeof(_type))
+
+#define MEM_Copy(dest,source,count) memcpy( (char*)(dest), (const char*)(source), (size_t)(count) )
+
+#define ERR(err) _hb_err (err)
+
+
+HB_INTERNAL HB_Pointer
+_hb_alloc( size_t size,
+ HB_Error *perror_ );
+
+HB_INTERNAL HB_Pointer
+_hb_realloc( HB_Pointer block,
+ size_t new_size,
+ HB_Error *perror_ );
+
+HB_INTERNAL void
+_hb_free( HB_Pointer block );
+
+
+/* helper func to set a breakpoint on */
+HB_INTERNAL HB_Error
+_hb_err (HB_Error code);
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_IMPL_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-indic.cpp b/third_party/harfbuzz/src/harfbuzz-indic.cpp
new file mode 100644
index 0000000..7104d2a
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-indic.cpp
@@ -0,0 +1,1852 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#define FLAG(x) (1 << (x))
+
+static HB_Bool isLetter(HB_UChar16 ucs)
+{
+ const int test = FLAG(HB_Letter_Uppercase) |
+ FLAG(HB_Letter_Lowercase) |
+ FLAG(HB_Letter_Titlecase) |
+ FLAG(HB_Letter_Modifier) |
+ FLAG(HB_Letter_Other);
+ return FLAG(HB_GetUnicodeCharCategory(ucs)) & test;
+}
+
+static HB_Bool isMark(HB_UChar16 ucs)
+{
+ const int test = FLAG(HB_Mark_NonSpacing) |
+ FLAG(HB_Mark_SpacingCombining) |
+ FLAG(HB_Mark_Enclosing);
+ return FLAG(HB_GetUnicodeCharCategory(ucs)) & test;
+}
+
+enum Form {
+ Invalid = 0x0,
+ UnknownForm = Invalid,
+ Consonant,
+ Nukta,
+ Halant,
+ Matra,
+ VowelMark,
+ StressMark,
+ IndependentVowel,
+ LengthMark,
+ Control,
+ Other
+};
+
+static const unsigned char indicForms[0xe00-0x900] = {
+ // Devangari
+ Invalid, VowelMark, VowelMark, VowelMark,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Matra, Matra, Matra,
+ Matra, Matra, Matra, Matra,
+ Matra, Halant, UnknownForm, UnknownForm,
+
+ Other, StressMark, StressMark, StressMark,
+ StressMark, UnknownForm, UnknownForm, UnknownForm,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ IndependentVowel, IndependentVowel, VowelMark, VowelMark,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Consonant,
+ Consonant, Consonant /* ??? */, Consonant, Consonant,
+
+ // Bengali
+ Invalid, VowelMark, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Invalid, Invalid, IndependentVowel,
+
+ IndependentVowel, Invalid, Invalid, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Invalid, Consonant, Invalid,
+ Invalid, Invalid, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Invalid, Invalid, Matra,
+ Matra, Invalid, Invalid, Matra,
+ Matra, Halant, Consonant, UnknownForm,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, VowelMark,
+ Invalid, Invalid, Invalid, Invalid,
+ Consonant, Consonant, Invalid, Consonant,
+
+ IndependentVowel, IndependentVowel, VowelMark, VowelMark,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Consonant, Consonant, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Gurmukhi
+ Invalid, VowelMark, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
+ Invalid, Invalid, Invalid, IndependentVowel,
+
+ IndependentVowel, Invalid, Invalid, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Invalid, Consonant, Consonant,
+ Invalid, Consonant, Consonant, Invalid,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Invalid,
+ Invalid, Invalid, Invalid, Matra,
+ Matra, Invalid, Invalid, Matra,
+ Matra, Halant, UnknownForm, UnknownForm,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, UnknownForm, UnknownForm, UnknownForm,
+ Invalid, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Invalid,
+
+ Other, Other, Invalid, Invalid,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ StressMark, StressMark, Consonant, Consonant,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Gujarati
+ Invalid, VowelMark, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, Invalid, IndependentVowel,
+
+ IndependentVowel, IndependentVowel, Invalid, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Invalid, Consonant, Consonant,
+ Invalid, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Matra, Invalid, Matra,
+ Matra, Matra, Invalid, Matra,
+ Matra, Halant, UnknownForm, UnknownForm,
+
+ Other, UnknownForm, UnknownForm, UnknownForm,
+ UnknownForm, UnknownForm, UnknownForm, UnknownForm,
+ UnknownForm, UnknownForm, UnknownForm, UnknownForm,
+ UnknownForm, UnknownForm, UnknownForm, UnknownForm,
+
+ IndependentVowel, IndependentVowel, VowelMark, VowelMark,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Oriya
+ Invalid, VowelMark, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Invalid, Invalid, IndependentVowel,
+
+ IndependentVowel, Invalid, Invalid, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Invalid, Consonant, Consonant,
+ Invalid, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Invalid, Invalid, Invalid, Matra,
+ Matra, Invalid, Invalid, Matra,
+ Matra, Halant, UnknownForm, UnknownForm,
+
+ Other, Invalid, Invalid, Invalid,
+ Invalid, UnknownForm, LengthMark, LengthMark,
+ Invalid, Invalid, Invalid, Invalid,
+ Consonant, Consonant, Invalid, Consonant,
+
+ IndependentVowel, IndependentVowel, Invalid, Invalid,
+ Invalid, Invalid, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Consonant, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ //Tamil
+ Invalid, Invalid, VowelMark, Other,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
+ Invalid, Invalid, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+ IndependentVowel, Consonant, Invalid, Invalid,
+ Invalid, Consonant, Consonant, Invalid,
+ Consonant, Invalid, Consonant, Consonant,
+
+ Invalid, Invalid, Invalid, Consonant,
+ Consonant, Invalid, Invalid, Invalid,
+ Consonant, Consonant, Consonant, Invalid,
+ Invalid, Invalid, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Invalid, Invalid, Matra, Matra,
+
+ Matra, Matra, Matra, Invalid,
+ Invalid, Invalid, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Halant, Invalid, Invalid,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, LengthMark,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Telugu
+ Invalid, VowelMark, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Invalid, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Invalid, Invalid, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Halant, Invalid, Invalid,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, LengthMark, Matra, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+
+ IndependentVowel, IndependentVowel, Invalid, Invalid,
+ Invalid, Invalid, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Kannada
+ Invalid, Invalid, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Invalid, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Nukta, Other, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Halant, Invalid, Invalid,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, LengthMark, LengthMark, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Consonant, Invalid,
+
+ IndependentVowel, IndependentVowel, VowelMark, VowelMark,
+ Invalid, Invalid, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Malayalam
+ Invalid, Invalid, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, Invalid, IndependentVowel, IndependentVowel,
+ IndependentVowel, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, UnknownForm, UnknownForm,
+ Invalid, Invalid, Matra, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Invalid, Invalid, Matra, Matra,
+ Matra, Invalid, Matra, Matra,
+ Matra, Halant, Invalid, Invalid,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, LengthMark,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+
+ IndependentVowel, IndependentVowel, Invalid, Invalid,
+ Invalid, Invalid, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+
+ // Sinhala
+ Invalid, Invalid, VowelMark, VowelMark,
+ Invalid, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+
+ IndependentVowel, IndependentVowel, IndependentVowel, IndependentVowel,
+ IndependentVowel, IndependentVowel, IndependentVowel, Invalid,
+ Invalid, Invalid, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+
+ Consonant, Consonant, Invalid, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Consonant,
+ Invalid, Consonant, Invalid, Invalid,
+
+ Consonant, Consonant, Consonant, Consonant,
+ Consonant, Consonant, Consonant, Invalid,
+ Invalid, Invalid, Halant, Invalid,
+ Invalid, Invalid, Invalid, Matra,
+
+ Matra, Matra, Matra, Matra,
+ Matra, Invalid, Matra, Invalid,
+ Matra, Matra, Matra, Matra,
+ Matra, Matra, Matra, Matra,
+
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+ Invalid, Invalid, Invalid, Invalid,
+
+ Invalid, Invalid, Matra, Matra,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+ Other, Other, Other, Other,
+};
+
+enum Position {
+ None,
+ Pre,
+ Above,
+ Below,
+ Post,
+ Split,
+ Base,
+ Reph,
+ Vattu,
+ Inherit
+};
+
+static const unsigned char indicPosition[0xe00-0x900] = {
+ // Devanagari
+ None, Above, Above, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ Below, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, Post, Pre,
+
+ Post, Below, Below, Below,
+ Below, Above, Above, Above,
+ Above, Post, Post, Post,
+ Post, None, None, None,
+
+ None, Above, Below, Above,
+ Above, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, Below, Below,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Bengali
+ None, Above, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ Below, None, None, Post,
+
+ Below, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ Below, None, Post, Pre,
+
+ Post, Below, Below, Below,
+ Below, None, None, Pre,
+ Pre, None, None, Split,
+ Split, Below, None, None,
+
+ None, None, None, None,
+ None, None, None, Post,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, Below, Below,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Gurmukhi
+ None, Above, Above, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, Post,
+
+ Below, None, None, None,
+ None, Below, None, None,
+ None, Below, None, None,
+ Below, None, Post, Pre,
+
+ Post, Below, Below, None,
+ None, None, None, Above,
+ Above, None, None, Above,
+ Above, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ Above, Above, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Gujarati
+ None, Above, Above, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ Below, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, Post, Pre,
+
+ Post, Below, Below, Below,
+ Below, Above, None, Above,
+ Above, Post, None, Post,
+ Post, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, Below, Below,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Oriya
+ None, Above, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ Below, None, None, None,
+ Below, None, None, None,
+ Below, Below, Below, Post,
+
+ Below, None, Below, Below,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, Post, Above,
+
+ Post, Below, Below, Below,
+ None, None, None, Pre,
+ Split, None, None, Split,
+ Split, None, None, None,
+
+ None, None, None, None,
+ None, None, Above, Post,
+ None, None, None, None,
+ None, None, None, Post,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, Below, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Tamil
+ None, None, Above, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, Post, Post,
+
+ Above, Below, Below, None,
+ None, None, Pre, Pre,
+ Pre, None, Split, Split,
+ Split, Halant, None, None,
+
+ None, None, None, None,
+ None, None, None, Post,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Telugu
+ None, Post, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, Below, Below, Below,
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+ Below, None, Below, Below,
+ Below, Below, Below, Below,
+
+ Below, None, Below, Below,
+ None, Below, Below, Below,
+ Below, Below, None, None,
+ None, None, Post, Above,
+
+ Above, Post, Post, Post,
+ Post, None, Above, Above,
+ Split, None, Post, Above,
+ Above, Halant, None, None,
+
+ None, None, None, None,
+ None, Above, Below, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Kannada
+ None, None, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, Below, Below, Below,
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+ Below, Below, Below, Below,
+
+ Below, None, Below, Below,
+ None, Below, Below, Below,
+ Below, Below, None, None,
+ None, None, Post, Above,
+
+ Split, Post, Post, Post,
+ Post, None, Above, Split,
+ Split, None, Split, Split,
+ Above, Halant, None, None,
+
+ None, None, None, None,
+ None, Post, Post, None,
+ None, None, None, None,
+ None, None, Below, None,
+
+ None, None, Below, Below,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Malayalam
+ None, None, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, Post,
+
+ Post, None, Below, None,
+ None, Post, None, None,
+ None, None, None, None,
+ None, None, Post, Post,
+
+ Post, Post, Post, Post,
+ None, None, Pre, Pre,
+ Pre, None, Split, Split,
+ Split, Halant, None, None,
+
+ None, None, None, None,
+ None, None, None, Post,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ // Sinhala
+ None, None, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, Post,
+
+ Post, Post, Above, Above,
+ Below, None, Below, None,
+ Post, Pre, Split, Pre,
+ Split, Split, Split, Post,
+
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None,
+
+ None, None, Post, Post,
+ None, None, None, None,
+ None, None, None, None,
+ None, None, None, None
+};
+
+static inline Form form(unsigned short uc) {
+ if (uc < 0x900 || uc > 0xdff) {
+ if (uc == 0x25cc)
+ return Consonant;
+ if (uc == 0x200c || uc == 0x200d)
+ return Control;
+ return Other;
+ }
+ return (Form)indicForms[uc-0x900];
+}
+
+static inline Position indic_position(unsigned short uc) {
+ if (uc < 0x900 || uc > 0xdff)
+ return None;
+ return (Position) indicPosition[uc-0x900];
+}
+
+
+enum IndicScriptProperties {
+ HasReph = 0x01,
+ HasSplit = 0x02
+};
+
+const hb_uint8 scriptProperties[10] = {
+ // Devanagari,
+ HasReph,
+ // Bengali,
+ HasReph|HasSplit,
+ // Gurmukhi,
+ 0,
+ // Gujarati,
+ HasReph,
+ // Oriya,
+ HasReph|HasSplit,
+ // Tamil,
+ HasSplit,
+ // Telugu,
+ HasSplit,
+ // Kannada,
+ HasSplit|HasReph,
+ // Malayalam,
+ HasSplit,
+ // Sinhala,
+ HasSplit
+};
+
+struct IndicOrdering {
+ Form form;
+ Position position;
+};
+
+static const IndicOrdering devanagari_order [] = {
+ { Consonant, Below },
+ { Matra, Below },
+ { VowelMark, Below },
+ { StressMark, Below },
+ { Matra, Above },
+ { Matra, Post },
+ { Consonant, Reph },
+ { VowelMark, Above },
+ { StressMark, Above },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering bengali_order [] = {
+ { Consonant, Below },
+ { Matra, Below },
+ { Matra, Above },
+ { Consonant, Reph },
+ { VowelMark, Above },
+ { Consonant, Post },
+ { Matra, Post },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering gurmukhi_order [] = {
+ { Consonant, Below },
+ { Matra, Below },
+ { Matra, Above },
+ { Consonant, Post },
+ { Matra, Post },
+ { VowelMark, Above },
+ { (Form)0, None }
+};
+
+static const IndicOrdering tamil_order [] = {
+ { Matra, Above },
+ { Matra, Post },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering telugu_order [] = {
+ { Matra, Above },
+ { Matra, Below },
+ { Matra, Post },
+ { Consonant, Below },
+ { Consonant, Post },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering kannada_order [] = {
+ { Matra, Above },
+ { Matra, Post },
+ { Consonant, Below },
+ { Consonant, Post },
+ { LengthMark, Post },
+ { Consonant, Reph },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering malayalam_order [] = {
+ { Consonant, Below },
+ { Matra, Below },
+ { Consonant, Reph },
+ { Consonant, Post },
+ { Matra, Post },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering sinhala_order [] = {
+ { Matra, Below },
+ { Matra, Above },
+ { Matra, Post },
+ { VowelMark, Post },
+ { (Form)0, None }
+};
+
+static const IndicOrdering * const indic_order[] = {
+ devanagari_order, // Devanagari
+ bengali_order, // Bengali
+ gurmukhi_order, // Gurmukhi
+ devanagari_order, // Gujarati
+ bengali_order, // Oriya
+ tamil_order, // Tamil
+ telugu_order, // Telugu
+ kannada_order, // Kannada
+ malayalam_order, // Malayalam
+ sinhala_order // Sinhala
+};
+
+
+
+// vowel matras that have to be split into two parts.
+static const unsigned short split_matras[] = {
+ // matra, split1, split2
+
+ // bengalis
+ 0x9cb, 0x9c7, 0x9be,
+ 0x9cc, 0x9c7, 0x9d7,
+ // oriya
+ 0xb48, 0xb47, 0xb56,
+ 0xb4b, 0xb47, 0xb3e,
+ 0xb4c, 0xb47, 0xb57,
+ // tamil
+ 0xbca, 0xbc6, 0xbbe,
+ 0xbcb, 0xbc7, 0xbbe,
+ 0xbcc, 0xbc6, 0xbd7,
+ // telugu
+ 0xc48, 0xc46, 0xc56,
+ // kannada
+ 0xcc0, 0xcbf, 0xcd5,
+ 0xcc7, 0xcc6, 0xcd5,
+ 0xcc8, 0xcc6, 0xcd6,
+ 0xcca, 0xcc6, 0xcc2,
+ 0xccb, 0xcca, 0xcd5,
+ // malayalam
+ 0xd4a, 0xd46, 0xd3e,
+ 0xd4b, 0xd47, 0xd3e,
+ 0xd4c, 0xd46, 0xd57,
+ // sinhala
+ 0xdda, 0xdd9, 0xdca,
+ 0xddc, 0xdd9, 0xdcf,
+ 0xddd, 0xddc, 0xdca,
+ 0xdde, 0xdd9, 0xddf,
+ 0xffff
+};
+
+static inline void splitMatra(unsigned short *reordered, int matra, int &len, int &base)
+{
+ unsigned short matra_uc = reordered[matra];
+ //qDebug("matra=%d, reordered[matra]=%x", matra, reordered[matra]);
+
+ const unsigned short *split = split_matras;
+ while (split[0] < matra_uc)
+ split += 3;
+
+ assert(*split == matra_uc);
+ ++split;
+
+ if (indic_position(*split) == Pre) {
+ reordered[matra] = split[1];
+ memmove(reordered + 1, reordered, len*sizeof(unsigned short));
+ reordered[0] = split[0];
+ base++;
+ } else {
+ memmove(reordered + matra + 1, reordered + matra, (len-matra)*sizeof(unsigned short));
+ reordered[matra] = split[0];
+ reordered[matra+1] = split[1];
+ }
+ len++;
+}
+
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature indic_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('i', 'n', 'i', 't'), InitProperty },
+ { HB_MAKE_TAG('n', 'u', 'k', 't'), NuktaProperty },
+ { HB_MAKE_TAG('a', 'k', 'h', 'n'), AkhantProperty },
+ { HB_MAKE_TAG('r', 'p', 'h', 'f'), RephProperty },
+ { HB_MAKE_TAG('b', 'l', 'w', 'f'), BelowFormProperty },
+ { HB_MAKE_TAG('h', 'a', 'l', 'f'), HalfFormProperty },
+ { HB_MAKE_TAG('p', 's', 't', 'f'), PostFormProperty },
+ { HB_MAKE_TAG('v', 'a', 't', 'u'), VattuProperty },
+ { HB_MAKE_TAG('p', 'r', 'e', 's'), PreSubstProperty },
+ { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
+ { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
+ { HB_MAKE_TAG('p', 's', 't', 's'), PostSubstProperty },
+ { HB_MAKE_TAG('h', 'a', 'l', 'n'), HalantProperty },
+ { 0, 0 }
+};
+#endif
+
+// #define INDIC_DEBUG
+#ifdef INDIC_DEBUG
+#define IDEBUG qDebug
+#else
+#define IDEBUG if(0) printf
+#endif
+
+#ifdef INDIC_DEBUG
+static QString propertiesToString(int properties)
+{
+ QString res;
+ properties = ~properties;
+ if (properties & CcmpProperty)
+ res += "Ccmp ";
+ if (properties & InitProperty)
+ res += "Init ";
+ if (properties & NuktaProperty)
+ res += "Nukta ";
+ if (properties & AkhantProperty)
+ res += "Akhant ";
+ if (properties & RephProperty)
+ res += "Reph ";
+ if (properties & PreFormProperty)
+ res += "PreForm ";
+ if (properties & BelowFormProperty)
+ res += "BelowForm ";
+ if (properties & AboveFormProperty)
+ res += "AboveForm ";
+ if (properties & HalfFormProperty)
+ res += "HalfForm ";
+ if (properties & PostFormProperty)
+ res += "PostForm ";
+ if (properties & VattuProperty)
+ res += "Vattu ";
+ if (properties & PreSubstProperty)
+ res += "PreSubst ";
+ if (properties & BelowSubstProperty)
+ res += "BelowSubst ";
+ if (properties & AboveSubstProperty)
+ res += "AboveSubst ";
+ if (properties & PostSubstProperty)
+ res += "PostSubst ";
+ if (properties & HalantProperty)
+ res += "Halant ";
+ if (properties & CligProperty)
+ res += "Clig ";
+ return res;
+}
+#endif
+
+static bool indic_shape_syllable(HB_Bool openType, HB_ShaperItem *item, bool invalid)
+{
+ HB_Script script = item->item.script;
+ assert(script >= HB_Script_Devanagari && script <= HB_Script_Sinhala);
+ const unsigned short script_base = 0x0900 + 0x80*(script-HB_Script_Devanagari);
+ const unsigned short ra = script_base + 0x30;
+ const unsigned short halant = script_base + 0x4d;
+ const unsigned short nukta = script_base + 0x3c;
+ bool control = false;
+
+ int len = (int)item->item.length;
+ IDEBUG(">>>>> indic shape: from=%d, len=%d invalid=%d", item->item.pos, item->item.length, invalid);
+
+ if ((int)item->num_glyphs < len+4) {
+ item->num_glyphs = len+4;
+ return false;
+ }
+
+ HB_STACKARRAY(HB_UChar16, reordered, len + 4);
+ HB_STACKARRAY(hb_uint8, position, len + 4);
+
+ unsigned char properties = scriptProperties[script-HB_Script_Devanagari];
+
+ if (invalid) {
+ *reordered = 0x25cc;
+ memcpy(reordered+1, item->string + item->item.pos, len*sizeof(HB_UChar16));
+ len++;
+ } else {
+ memcpy(reordered, item->string + item->item.pos, len*sizeof(HB_UChar16));
+ }
+ if (reordered[len-1] == 0x200c) // zero width non joiner
+ len--;
+
+ int i;
+ int base = 0;
+ int reph = -1;
+
+#ifdef INDIC_DEBUG
+ IDEBUG("original:");
+ for (i = 0; i < len; i++) {
+ IDEBUG(" %d: %4x", i, reordered[i]);
+ }
+#endif
+
+ if (len != 1) {
+ HB_UChar16 *uc = reordered;
+ bool beginsWithRa = false;
+
+ // Rule 1: find base consonant
+ //
+ // The shaping engine finds the base consonant of the
+ // syllable, using the following algorithm: starting from the
+ // end of the syllable, move backwards until a consonant is
+ // found that does not have a below-base or post-base form
+ // (post-base forms have to follow below-base forms), or
+ // arrive at the first consonant. The consonant stopped at
+ // will be the base.
+ //
+ // * If the syllable starts with Ra + H (in a script that has
+ // 'Reph'), Ra is excluded from candidates for base
+ // consonants.
+ //
+ // * In Kannada and Telugu, the base consonant cannot be
+ // farther than 3 consonants from the end of the syllable.
+ // #### replace the HasReph property by testing if the feature exists in the font!
+ if (form(*uc) == Consonant || (script == HB_Script_Bengali && form(*uc) == IndependentVowel)) {
+ beginsWithRa = (properties & HasReph) && ((len > 2) && *uc == ra && *(uc+1) == halant);
+
+ if (beginsWithRa && form(*(uc+2)) == Control)
+ beginsWithRa = false;
+
+ base = (beginsWithRa ? 2 : 0);
+ IDEBUG(" length = %d, beginsWithRa = %d, base=%d", len, beginsWithRa, base);
+
+ int lastConsonant = 0;
+ int matra = -1;
+ // we remember:
+ // * the last consonant since we need it for rule 2
+ // * the matras position for rule 3 and 4
+
+ // figure out possible base glyphs
+ memset(position, 0, len);
+ if (script == HB_Script_Devanagari || script == HB_Script_Gujarati) {
+ bool vattu = false;
+ for (i = base; i < len; ++i) {
+ position[i] = form(uc[i]);
+ if (position[i] == Consonant) {
+ lastConsonant = i;
+ vattu = (!vattu && uc[i] == ra);
+ if (vattu) {
+ IDEBUG("excluding vattu glyph at %d from base candidates", i);
+ position[i] = Vattu;
+ }
+ } else if (position[i] == Matra) {
+ matra = i;
+ }
+ }
+ } else {
+ for (i = base; i < len; ++i) {
+ position[i] = form(uc[i]);
+ if (position[i] == Consonant)
+ lastConsonant = i;
+ else if (matra < 0 && position[i] == Matra)
+ matra = i;
+ }
+ }
+ int skipped = 0;
+ Position pos = Post;
+ for (i = len-1; i > base; i--) {
+ if (position[i] != Consonant && (position[i] != Control || script == HB_Script_Kannada))
+ continue;
+
+ Position charPosition = indic_position(uc[i]);
+ if (pos == Post && charPosition == Post) {
+ pos = Post;
+ } else if ((pos == Post || pos == Below) && charPosition == Below) {
+ if (script == HB_Script_Devanagari || script == HB_Script_Gujarati)
+ base = i;
+ pos = Below;
+ } else {
+ base = i;
+ break;
+ }
+ if (skipped == 2 && (script == HB_Script_Kannada || script == HB_Script_Telugu)) {
+ base = i;
+ break;
+ }
+ ++skipped;
+ }
+
+ IDEBUG(" base consonant at %d skipped=%d, lastConsonant=%d", base, skipped, lastConsonant);
+
+ // Rule 2:
+ //
+ // If the base consonant is not the last one, Uniscribe
+ // moves the halant from the base consonant to the last
+ // one.
+ if (lastConsonant > base) {
+ int halantPos = 0;
+ if (uc[base+1] == halant)
+ halantPos = base + 1;
+ else if (uc[base+1] == nukta && uc[base+2] == halant)
+ halantPos = base + 2;
+ if (halantPos > 0) {
+ IDEBUG(" moving halant from %d to %d!", base+1, lastConsonant);
+ for (i = halantPos; i < lastConsonant; i++)
+ uc[i] = uc[i+1];
+ uc[lastConsonant] = halant;
+ }
+ }
+
+ // Rule 3:
+ //
+ // If the syllable starts with Ra + H, Uniscribe moves
+ // this combination so that it follows either:
+
+ // * the post-base 'matra' (if any) or the base consonant
+ // (in scripts that show similarity to Devanagari, i.e.,
+ // Devanagari, Gujarati, Bengali)
+ // * the base consonant (other scripts)
+ // * the end of the syllable (Kannada)
+
+ Position matra_position = None;
+ if (matra > 0)
+ matra_position = indic_position(uc[matra]);
+ IDEBUG(" matra at %d with form %d, base=%d", matra, matra_position, base);
+
+ if (beginsWithRa && base != 0) {
+ int toPos = base+1;
+ if (toPos < len && uc[toPos] == nukta)
+ toPos++;
+ if (toPos < len && uc[toPos] == halant)
+ toPos++;
+ if (toPos < len && uc[toPos] == 0x200d)
+ toPos++;
+ if (toPos < len-1 && uc[toPos] == ra && uc[toPos+1] == halant)
+ toPos += 2;
+ if (script == HB_Script_Devanagari || script == HB_Script_Gujarati || script == HB_Script_Bengali) {
+ if (matra_position == Post || matra_position == Split) {
+ toPos = matra+1;
+ matra -= 2;
+ }
+ } else if (script == HB_Script_Kannada) {
+ toPos = len;
+ matra -= 2;
+ }
+
+ IDEBUG("moving leading ra+halant to position %d", toPos);
+ for (i = 2; i < toPos; i++)
+ uc[i-2] = uc[i];
+ uc[toPos-2] = ra;
+ uc[toPos-1] = halant;
+ base -= 2;
+ if (properties & HasReph)
+ reph = toPos-2;
+ }
+
+ // Rule 4:
+
+ // Uniscribe splits two- or three-part matras into their
+ // parts. This splitting is a character-to-character
+ // operation).
+ //
+ // Uniscribe describes some moving operations for these
+ // matras here. For shaping however all pre matras need
+ // to be at the beginning of the syllable, so we just move
+ // them there now.
+ if (matra_position == Split) {
+ splitMatra(uc, matra, len, base);
+ // Handle three-part matras (0xccb in Kannada)
+ matra_position = indic_position(uc[matra]);
+ if (matra_position == Split)
+ splitMatra(uc, matra, len, base);
+ } else if (matra_position == Pre) {
+ unsigned short m = uc[matra];
+ while (matra--)
+ uc[matra+1] = uc[matra];
+ uc[0] = m;
+ base++;
+ }
+ }
+
+ // Rule 5:
+ //
+ // Uniscribe classifies consonants and 'matra' parts as
+ // pre-base, above-base (Reph), below-base or post-base. This
+ // classification exists on the character code level and is
+ // language-dependent, not font-dependent.
+ for (i = 0; i < base; ++i)
+ position[i] = Pre;
+ position[base] = Base;
+ for (i = base+1; i < len; ++i) {
+ position[i] = indic_position(uc[i]);
+ // #### replace by adjusting table
+ if (uc[i] == nukta || uc[i] == halant)
+ position[i] = Inherit;
+ }
+ if (reph > 0) {
+ // recalculate reph, it might have changed.
+ for (i = base+1; i < len; ++i)
+ if (uc[i] == ra)
+ reph = i;
+ position[reph] = Reph;
+ position[reph+1] = Inherit;
+ }
+
+ // all reordering happens now to the chars after the base
+ int fixed = base+1;
+ if (fixed < len && uc[fixed] == nukta)
+ fixed++;
+ if (fixed < len && uc[fixed] == halant)
+ fixed++;
+ if (fixed < len && uc[fixed] == 0x200d)
+ fixed++;
+
+#ifdef INDIC_DEBUG
+ for (i = fixed; i < len; ++i)
+ IDEBUG("position[%d] = %d, form=%d uc=%x", i, position[i], form(uc[i]), uc[i]);
+#endif
+ // we continuosly position the matras and vowel marks and increase the fixed
+ // until we reached the end.
+ const IndicOrdering *finalOrder = indic_order[script-HB_Script_Devanagari];
+
+ IDEBUG(" reordering pass:");
+ IDEBUG(" base=%d fixed=%d", base, fixed);
+ int toMove = 0;
+ while (finalOrder[toMove].form && fixed < len-1) {
+ IDEBUG(" fixed = %d, toMove=%d, moving form %d with pos %d", fixed, toMove, finalOrder[toMove].form, finalOrder[toMove].position);
+ for (i = fixed; i < len; i++) {
+// IDEBUG() << " i=" << i << "uc=" << hex << uc[i] << "form=" << form(uc[i])
+// << "position=" << position[i];
+ if (form(uc[i]) == finalOrder[toMove].form &&
+ position[i] == finalOrder[toMove].position) {
+ // need to move this glyph
+ int to = fixed;
+ if (i < len-1 && position[i+1] == Inherit) {
+ IDEBUG(" moving two chars from %d to %d", i, to);
+ unsigned short ch = uc[i];
+ unsigned short ch2 = uc[i+1];
+ unsigned char pos = position[i];
+ for (int j = i+1; j > to+1; j--) {
+ uc[j] = uc[j-2];
+ position[j] = position[j-2];
+ }
+ uc[to] = ch;
+ uc[to+1] = ch2;
+ position[to] = pos;
+ position[to+1] = pos;
+ fixed += 2;
+ } else {
+ IDEBUG(" moving one char from %d to %d", i, to);
+ unsigned short ch = uc[i];
+ unsigned char pos = position[i];
+ for (int j = i; j > to; j--) {
+ uc[j] = uc[j-1];
+ position[j] = position[j-1];
+ }
+ uc[to] = ch;
+ position[to] = pos;
+ fixed++;
+ }
+ }
+ }
+ toMove++;
+ }
+
+ }
+
+ if (reph > 0) {
+ // recalculate reph, it might have changed.
+ for (i = base+1; i < len; ++i)
+ if (reordered[i] == ra)
+ reph = i;
+ }
+
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+ if (!item->font->klass->convertStringToGlyphIndices(item->font,
+ reordered, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2))
+ goto error;
+
+
+ IDEBUG(" base=%d, reph=%d", base, reph);
+ IDEBUG("reordered:");
+ for (i = 0; i < len; i++) {
+ item->attributes[i].mark = false;
+ item->attributes[i].clusterStart = false;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = false;
+ IDEBUG(" %d: %4x", i, reordered[i]);
+ }
+
+ // now we have the syllable in the right order, and can start running it through open type.
+
+ for (i = 0; i < len; ++i)
+ control |= (form(reordered[i]) == Control);
+
+#ifndef NO_OPENTYPE
+ if (openType) {
+
+ // we need to keep track of where the base glyph is for some
+ // scripts and use the cluster feature for this. This
+ // also means we have to correct the logCluster output from
+ // the open type engine manually afterwards. for indic this
+ // is rather simple, as all chars just point to the first
+ // glyph in the syllable.
+ HB_STACKARRAY(unsigned short, clusters, len);
+ HB_STACKARRAY(unsigned int, properties, len);
+
+ for (i = 0; i < len; ++i)
+ clusters[i] = i;
+
+ // features we should always apply
+ for (i = 0; i < len; ++i)
+ properties[i] = ~(CcmpProperty
+ | NuktaProperty
+ | VattuProperty
+ | PreSubstProperty
+ | BelowSubstProperty
+ | AboveSubstProperty
+ | HalantProperty
+ | PositioningProperties);
+
+ // Ccmp always applies
+ // Init
+ if (item->item.pos == 0
+ || !(isLetter(item->string[item->item.pos-1]) || isMark(item->string[item->item.pos-1])))
+ properties[0] &= ~InitProperty;
+
+ // Nukta always applies
+ // Akhant
+ for (i = 0; i <= base; ++i)
+ properties[i] &= ~AkhantProperty;
+ // Reph
+ if (reph >= 0) {
+ properties[reph] &= ~RephProperty;
+ properties[reph+1] &= ~RephProperty;
+ }
+ // BelowForm
+ for (i = base+1; i < len; ++i)
+ properties[i] &= ~BelowFormProperty;
+
+ if (script == HB_Script_Devanagari || script == HB_Script_Gujarati) {
+ // vattu glyphs need this aswell
+ bool vattu = false;
+ for (i = base-2; i > 1; --i) {
+ if (form(reordered[i]) == Consonant) {
+ vattu = (!vattu && reordered[i] == ra);
+ if (vattu) {
+ IDEBUG("forming vattu ligature at %d", i);
+ properties[i] &= ~BelowFormProperty;
+ properties[i+1] &= ~BelowFormProperty;
+ }
+ }
+ }
+ }
+ // HalfFormProperty
+ for (i = 0; i < base; ++i)
+ properties[i] &= ~HalfFormProperty;
+ if (control) {
+ for (i = 2; i < len; ++i) {
+ if (reordered[i] == 0x200d /* ZWJ */) {
+ properties[i-1] &= ~HalfFormProperty;
+ properties[i-2] &= ~HalfFormProperty;
+ } else if (reordered[i] == 0x200c /* ZWNJ */) {
+ properties[i-1] &= ~HalfFormProperty;
+ properties[i-2] &= ~HalfFormProperty;
+ }
+ }
+ }
+ // PostFormProperty
+ for (i = base+1; i < len; ++i)
+ properties[i] &= ~PostFormProperty;
+ // vattu always applies
+ // pres always applies
+ // blws always applies
+ // abvs always applies
+
+ // psts
+ // ### this looks slightly different from before, but I believe it's correct
+ if (reordered[len-1] != halant || base != len-2)
+ properties[base] &= ~PostSubstProperty;
+ for (i = base+1; i < len; ++i)
+ properties[i] &= ~PostSubstProperty;
+
+ // halant always applies
+
+#ifdef INDIC_DEBUG
+ {
+ IDEBUG("OT properties:");
+ for (int i = 0; i < len; ++i)
+ qDebug(" i: %s", ::propertiesToString(properties[i]).toLatin1().data());
+ }
+#endif
+
+ // initialize
+ item->log_clusters = clusters;
+ HB_OpenTypeShape(item, properties);
+
+ int newLen = item->face->buffer->in_length;
+ HB_GlyphItem otl_glyphs = item->face->buffer->in_string;
+
+ // move the left matra back to its correct position in malayalam and tamil
+ if ((script == HB_Script_Malayalam || script == HB_Script_Tamil) && (form(reordered[0]) == Matra)) {
+// qDebug("reordering matra, len=%d", newLen);
+ // need to find the base in the shaped string and move the matra there
+ int basePos = 0;
+ while (basePos < newLen && (int)otl_glyphs[basePos].cluster <= base)
+ basePos++;
+ --basePos;
+ if (basePos < newLen && basePos > 1) {
+// qDebug("moving prebase matra to position %d in syllable newlen=%d", basePos, newLen);
+ HB_GlyphItemRec m = otl_glyphs[0];
+ --basePos;
+ for (i = 0; i < basePos; ++i)
+ otl_glyphs[i] = otl_glyphs[i+1];
+ otl_glyphs[basePos] = m;
+ }
+ }
+
+ HB_Bool positioned = HB_OpenTypePosition(item, availableGlyphs, false);
+
+ HB_FREE_STACKARRAY(clusters);
+ HB_FREE_STACKARRAY(properties);
+
+ if (!positioned)
+ goto error;
+
+ if (control) {
+ IDEBUG("found a control char in the syllable");
+ hb_uint32 i = 0, j = 0;
+ while (i < item->num_glyphs) {
+ if (form(reordered[otl_glyphs[i].cluster]) == Control) {
+ ++i;
+ if (i >= item->num_glyphs)
+ break;
+ }
+ item->glyphs[j] = item->glyphs[i];
+ item->attributes[j] = item->attributes[i];
+ ++i;
+ ++j;
+ }
+ item->num_glyphs = j;
+ }
+
+ } else {
+ HB_HeuristicPosition(item);
+ }
+#endif // NO_OPENTYPE
+ item->attributes[0].clusterStart = true;
+
+ HB_FREE_STACKARRAY(reordered);
+ HB_FREE_STACKARRAY(position);
+
+ IDEBUG("<<<<<<");
+ return true;
+
+error:
+ HB_FREE_STACKARRAY(reordered);
+ HB_FREE_STACKARRAY(position);
+ return false;
+}
+
+/* syllables are of the form:
+
+ (Consonant Nukta? Halant)* Consonant Matra? VowelMark? StressMark?
+ (Consonant Nukta? Halant)* Consonant Halant
+ IndependentVowel VowelMark? StressMark?
+
+ We return syllable boundaries on invalid combinations aswell
+*/
+static int indic_nextSyllableBoundary(HB_Script script, const HB_UChar16 *s, int start, int end, bool *invalid)
+{
+ *invalid = false;
+ IDEBUG("indic_nextSyllableBoundary: start=%d, end=%d", start, end);
+ const HB_UChar16 *uc = s+start;
+
+ int pos = 0;
+ Form state = form(uc[pos]);
+ IDEBUG("state[%d]=%d (uc=%4x)", pos, state, uc[pos]);
+ pos++;
+
+ if (state != Consonant && state != IndependentVowel) {
+ if (state != Other)
+ *invalid = true;
+ goto finish;
+ }
+
+ while (pos < end - start) {
+ Form newState = form(uc[pos]);
+ IDEBUG("state[%d]=%d (uc=%4x)", pos, newState, uc[pos]);
+ switch(newState) {
+ case Control:
+ newState = state;
+ if (state == Halant && uc[pos] == 0x200d /* ZWJ */)
+ break;
+ // the control character should be the last char in the item
+ ++pos;
+ goto finish;
+ case Consonant:
+ if (state == Halant && (script != HB_Script_Sinhala || uc[pos-1] == 0x200d /* ZWJ */))
+ break;
+ goto finish;
+ case Halant:
+ if (state == Nukta || state == Consonant)
+ break;
+ // Bengali has a special exception allowing the combination Vowel_A/E + Halant + Ya
+ if (script == HB_Script_Bengali && pos == 1 &&
+ (uc[0] == 0x0985 || uc[0] == 0x098f))
+ break;
+ goto finish;
+ case Nukta:
+ if (state == Consonant)
+ break;
+ goto finish;
+ case StressMark:
+ if (state == VowelMark)
+ break;
+ // fall through
+ case VowelMark:
+ if (state == Matra || state == IndependentVowel)
+ break;
+ // fall through
+ case Matra:
+ if (state == Consonant || state == Nukta)
+ break;
+ // ### not sure if this is correct. If it is, does it apply only to Bengali or should
+ // it work for all Indic languages?
+ // the combination Independent_A + Vowel Sign AA is allowed.
+ if (script == HB_Script_Bengali && uc[pos] == 0x9be && uc[pos-1] == 0x985)
+ break;
+ if (script == HB_Script_Tamil && state == Matra) {
+ if (uc[pos-1] == 0x0bc6 &&
+ (uc[pos] == 0xbbe || uc[pos] == 0xbd7))
+ break;
+ if (uc[pos-1] == 0x0bc7 && uc[pos] == 0xbbe)
+ break;
+ }
+ goto finish;
+
+ case LengthMark:
+ case IndependentVowel:
+ case Invalid:
+ case Other:
+ goto finish;
+ }
+ state = newState;
+ pos++;
+ }
+ finish:
+ return pos+start;
+}
+
+HB_Bool HB_IndicShape(HB_ShaperItem *item)
+{
+ assert(item->item.script >= HB_Script_Devanagari && item->item.script <= HB_Script_Sinhala);
+
+ HB_Bool openType = false;
+#ifndef NO_OPENTYPE
+ openType = HB_SelectScript(item, indic_features);
+#endif
+ unsigned short *logClusters = item->log_clusters;
+
+ HB_ShaperItem syllable = *item;
+ int first_glyph = 0;
+
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+ IDEBUG("indic_shape: from %d length %d", item->item.pos, item->item.length);
+ while (sstart < end) {
+ bool invalid;
+ int send = indic_nextSyllableBoundary(item->item.script, item->string, sstart, end, &invalid);
+ IDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
+ invalid ? "true" : "false");
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!indic_shape_syllable(openType, &syllable, invalid)) {
+ IDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
+ item->num_glyphs += syllable.num_glyphs;
+ return false;
+ }
+ // fix logcluster array
+ IDEBUG("syllable:");
+ hb_uint32 g;
+ for (g = first_glyph; g < first_glyph + syllable.num_glyphs; ++g)
+ IDEBUG(" %d -> glyph %x", g, item->glyphs[g]);
+ IDEBUG(" logclusters:");
+ int i;
+ for (i = sstart; i < send; ++i) {
+ IDEBUG(" %d -> glyph %d", i, first_glyph);
+ logClusters[i-item->item.pos] = first_glyph;
+ }
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return true;
+}
+
+void HB_IndicAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ int end = from + len;
+ const HB_UChar16 *uc = text + from;
+ attributes += from;
+ hb_uint32 i = 0;
+ while (i < len) {
+ bool invalid;
+ hb_uint32 boundary = indic_nextSyllableBoundary(script, text, from+i, end, &invalid) - from;
+ attributes[i].charStop = true;
+
+ if (boundary > len-1) boundary = len;
+ i++;
+ while (i < boundary) {
+ attributes[i].charStop = false;
+ ++uc;
+ ++i;
+ }
+ assert(i == boundary);
+ }
+
+
+}
+
+
diff --git a/third_party/harfbuzz/src/harfbuzz-khmer.c b/third_party/harfbuzz/src/harfbuzz-khmer.c
new file mode 100644
index 0000000..958069e
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-khmer.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+/*
+// Vocabulary
+// Base -> A consonant or an independent vowel in its full (not subscript) form. It is the
+// center of the syllable, it can be surrounded by coeng (subscript) consonants, vowels,
+// split vowels, signs... but there is only one base in a syllable, it has to be coded as
+// the first character of the syllable.
+// split vowel --> vowel that has two parts placed separately (e.g. Before and after the consonant).
+// Khmer language has five of them. Khmer split vowels either have one part before the
+// base and one after the base or they have a part before the base and a part above the base.
+// The first part of all Khmer split vowels is the same character, identical to
+// the glyph of Khmer dependent vowel SRA EI
+// coeng --> modifier used in Khmer to construct coeng (subscript) consonants
+// Differently than indian languages, the coeng modifies the consonant that follows it,
+// not the one preceding it Each consonant has two forms, the base form and the subscript form
+// the base form is the normal one (using the consonants code-point), the subscript form is
+// displayed when the combination coeng + consonant is encountered.
+// Consonant of type 1 -> A consonant which has subscript for that only occupies space under a base consonant
+// Consonant of type 2.-> Its subscript form occupies space under and before the base (only one, RO)
+// Consonant of Type 3 -> Its subscript form occupies space under and after the base (KHO, CHHO, THHO, BA, YO, SA)
+// Consonant shifter -> Khmer has to series of consonants. The same dependent vowel has different sounds
+// if it is attached to a consonant of the first series or a consonant of the second series
+// Most consonants have an equivalent in the other series, but some of theme exist only in
+// one series (for example SA). If we want to use the consonant SA with a vowel sound that
+// can only be done with a vowel sound that corresponds to a vowel accompanying a consonant
+// of the other series, then we need to use a consonant shifter: TRIISAP or MUSIKATOAN
+// x17C9 y x17CA. TRIISAP changes a first series consonant to second series sound and
+// MUSIKATOAN a second series consonant to have a first series vowel sound.
+// Consonant shifter are both normally supercript marks, but, when they are followed by a
+// superscript, they change shape and take the form of subscript dependent vowel SRA U.
+// If they are in the same syllable as a coeng consonant, Unicode 3.0 says that they
+// should be typed before the coeng. Unicode 4.0 breaks the standard and says that it should
+// be placed after the coeng consonant.
+// Dependent vowel -> In khmer dependent vowels can be placed above, below, before or after the base
+// Each vowel has its own position. Only one vowel per syllable is allowed.
+// Signs -> Khmer has above signs and post signs. Only one above sign and/or one post sign are
+// Allowed in a syllable.
+//
+//
+// order is important here! This order must be the same that is found in each horizontal
+// line in the statetable for Khmer (see khmerStateTable) .
+*/
+enum KhmerCharClassValues {
+ CC_RESERVED = 0,
+ CC_CONSONANT = 1, /* Consonant of type 1 or independent vowel */
+ CC_CONSONANT2 = 2, /* Consonant of type 2 */
+ CC_CONSONANT3 = 3, /* Consonant of type 3 */
+ CC_ZERO_WIDTH_NJ_MARK = 4, /* Zero Width non joiner character (0x200C) */
+ CC_CONSONANT_SHIFTER = 5,
+ CC_ROBAT = 6, /* Khmer special diacritic accent -treated differently in state table */
+ CC_COENG = 7, /* Subscript consonant combining character */
+ CC_DEPENDENT_VOWEL = 8,
+ CC_SIGN_ABOVE = 9,
+ CC_SIGN_AFTER = 10,
+ CC_ZERO_WIDTH_J_MARK = 11, /* Zero width joiner character */
+ CC_COUNT = 12 /* This is the number of character classes */
+};
+
+
+enum KhmerCharClassFlags {
+ CF_CLASS_MASK = 0x0000FFFF,
+
+ CF_CONSONANT = 0x01000000, /* flag to speed up comparing */
+ CF_SPLIT_VOWEL = 0x02000000, /* flag for a split vowel -> the first part is added in front of the syllable */
+ CF_DOTTED_CIRCLE = 0x04000000, /* add a dotted circle if a character with this flag is the first in a syllable */
+ CF_COENG = 0x08000000, /* flag to speed up comparing */
+ CF_SHIFTER = 0x10000000, /* flag to speed up comparing */
+ CF_ABOVE_VOWEL = 0x20000000, /* flag to speed up comparing */
+
+ /* position flags */
+ CF_POS_BEFORE = 0x00080000,
+ CF_POS_BELOW = 0x00040000,
+ CF_POS_ABOVE = 0x00020000,
+ CF_POS_AFTER = 0x00010000,
+ CF_POS_MASK = 0x000f0000
+};
+
+
+/* Characters that get referred to by name */
+enum KhmerChar {
+ C_SIGN_ZWNJ = 0x200C,
+ C_SIGN_ZWJ = 0x200D,
+ C_RO = 0x179A,
+ C_VOWEL_AA = 0x17B6,
+ C_SIGN_NIKAHIT = 0x17C6,
+ C_VOWEL_E = 0x17C1,
+ C_COENG = 0x17D2
+};
+
+
+/*
+// simple classes, they are used in the statetable (in this file) to control the length of a syllable
+// they are also used to know where a character should be placed (location in reference to the base character)
+// and also to know if a character, when independently displayed, should be displayed with a dotted-circle to
+// indicate error in syllable construction
+*/
+enum {
+ _xx = CC_RESERVED,
+ _sa = CC_SIGN_ABOVE | CF_DOTTED_CIRCLE | CF_POS_ABOVE,
+ _sp = CC_SIGN_AFTER | CF_DOTTED_CIRCLE| CF_POS_AFTER,
+ _c1 = CC_CONSONANT | CF_CONSONANT,
+ _c2 = CC_CONSONANT2 | CF_CONSONANT,
+ _c3 = CC_CONSONANT3 | CF_CONSONANT,
+ _rb = CC_ROBAT | CF_POS_ABOVE | CF_DOTTED_CIRCLE,
+ _cs = CC_CONSONANT_SHIFTER | CF_DOTTED_CIRCLE | CF_SHIFTER,
+ _dl = CC_DEPENDENT_VOWEL | CF_POS_BEFORE | CF_DOTTED_CIRCLE,
+ _db = CC_DEPENDENT_VOWEL | CF_POS_BELOW | CF_DOTTED_CIRCLE,
+ _da = CC_DEPENDENT_VOWEL | CF_POS_ABOVE | CF_DOTTED_CIRCLE | CF_ABOVE_VOWEL,
+ _dr = CC_DEPENDENT_VOWEL | CF_POS_AFTER | CF_DOTTED_CIRCLE,
+ _co = CC_COENG | CF_COENG | CF_DOTTED_CIRCLE,
+
+ /* split vowel */
+ _va = _da | CF_SPLIT_VOWEL,
+ _vr = _dr | CF_SPLIT_VOWEL
+};
+
+
+/*
+// Character class: a character class value
+// ORed with character class flags.
+*/
+typedef unsigned long KhmerCharClass;
+
+
+/*
+// Character class tables
+// _xx character does not combine into syllable, such as numbers, puntuation marks, non-Khmer signs...
+// _sa Sign placed above the base
+// _sp Sign placed after the base
+// _c1 Consonant of type 1 or independent vowel (independent vowels behave as type 1 consonants)
+// _c2 Consonant of type 2 (only RO)
+// _c3 Consonant of type 3
+// _rb Khmer sign robat u17CC. combining mark for subscript consonants
+// _cd Consonant-shifter
+// _dl Dependent vowel placed before the base (left of the base)
+// _db Dependent vowel placed below the base
+// _da Dependent vowel placed above the base
+// _dr Dependent vowel placed behind the base (right of the base)
+// _co Khmer combining mark COENG u17D2, combines with the consonant or independent vowel following
+// it to create a subscript consonant or independent vowel
+// _va Khmer split vowel in which the first part is before the base and the second one above the base
+// _vr Khmer split vowel in which the first part is before the base and the second one behind (right of) the base
+*/
+static const KhmerCharClass khmerCharClasses[] = {
+ _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c1, _c1, /* 1780 - 178F */
+ _c1, _c1, _c1, _c1, _c3, _c1, _c1, _c1, _c1, _c3, _c2, _c1, _c1, _c1, _c3, _c3, /* 1790 - 179F */
+ _c1, _c3, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, _c1, /* 17A0 - 17AF */
+ _c1, _c1, _c1, _c1, _dr, _dr, _dr, _da, _da, _da, _da, _db, _db, _db, _va, _vr, /* 17B0 - 17BF */
+ _vr, _dl, _dl, _dl, _vr, _vr, _sa, _sp, _sp, _cs, _cs, _sa, _rb, _sa, _sa, _sa, /* 17C0 - 17CF */
+ _sa, _sa, _co, _sa, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _xx, _sa, _xx, _xx /* 17D0 - 17DF */
+};
+
+/* this enum must reflect the range of khmerCharClasses */
+enum KhmerCharClassesRange {
+ KhmerFirstChar = 0x1780,
+ KhmerLastChar = 0x17df
+};
+
+/*
+// Below we define how a character in the input string is either in the khmerCharClasses table
+// (in which case we get its type back), a ZWJ or ZWNJ (two characters that may appear
+// within the syllable, but are not in the table) we also get their type back, or an unknown object
+// in which case we get _xx (CC_RESERVED) back
+*/
+static KhmerCharClass getKhmerCharClass(HB_UChar16 uc)
+{
+ if (uc == C_SIGN_ZWJ) {
+ return CC_ZERO_WIDTH_J_MARK;
+ }
+
+ if (uc == C_SIGN_ZWNJ) {
+ return CC_ZERO_WIDTH_NJ_MARK;
+ }
+
+ if (uc < KhmerFirstChar || uc > KhmerLastChar) {
+ return CC_RESERVED;
+ }
+
+ return khmerCharClasses[uc - KhmerFirstChar];
+}
+
+
+/*
+// The stateTable is used to calculate the end (the length) of a well
+// formed Khmer Syllable.
+//
+// Each horizontal line is ordered exactly the same way as the values in KhmerClassTable
+// CharClassValues. This coincidence of values allows the follow up of the table.
+//
+// Each line corresponds to a state, which does not necessarily need to be a type
+// of component... for example, state 2 is a base, with is always a first character
+// in the syllable, but the state could be produced a consonant of any type when
+// it is the first character that is analysed (in ground state).
+//
+// Differentiating 3 types of consonants is necessary in order to
+// forbid the use of certain combinations, such as having a second
+// coeng after a coeng RO,
+// The inexistent possibility of having a type 3 after another type 3 is permitted,
+// eliminating it would very much complicate the table, and it does not create typing
+// problems, as the case above.
+//
+// The table is quite complex, in order to limit the number of coeng consonants
+// to 2 (by means of the table).
+//
+// There a peculiarity, as far as Unicode is concerned:
+// - The consonant-shifter is considered in two possible different
+// locations, the one considered in Unicode 3.0 and the one considered in
+// Unicode 4.0. (there is a backwards compatibility problem in this standard).
+//
+//
+// xx independent character, such as a number, punctuation sign or non-khmer char
+//
+// c1 Khmer consonant of type 1 or an independent vowel
+// that is, a letter in which the subscript for is only under the
+// base, not taking any space to the right or to the left
+//
+// c2 Khmer consonant of type 2, the coeng form takes space under
+// and to the left of the base (only RO is of this type)
+//
+// c3 Khmer consonant of type 3. Its subscript form takes space under
+// and to the right of the base.
+//
+// cs Khmer consonant shifter
+//
+// rb Khmer robat
+//
+// co coeng character (u17D2)
+//
+// dv dependent vowel (including split vowels, they are treated in the same way).
+// even if dv is not defined above, the component that is really tested for is
+// KhmerClassTable::CC_DEPENDENT_VOWEL, which is common to all dependent vowels
+//
+// zwj Zero Width joiner
+//
+// zwnj Zero width non joiner
+//
+// sa above sign
+//
+// sp post sign
+//
+// there are lines with equal content but for an easier understanding
+// (and maybe change in the future) we did not join them
+*/
+static const signed char khmerStateTable[][CC_COUNT] =
+{
+ /* xx c1 c2 c3 zwnj cs rb co dv sa sp zwj */
+ { 1, 2, 2, 2, 1, 1, 1, 6, 1, 1, 1, 2}, /* 0 - ground state */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 1 - exit state (or sign to the right of the syllable) */
+ {-1, -1, -1, -1, 3, 4, 5, 6, 16, 17, 1, -1}, /* 2 - Base consonant */
+ {-1, -1, -1, -1, -1, 4, -1, -1, 16, -1, -1, -1}, /* 3 - First ZWNJ before a register shifter It can only be followed by a shifter or a vowel */
+ {-1, -1, -1, -1, 15, -1, -1, 6, 16, 17, 1, 14}, /* 4 - First register shifter */
+ {-1, -1, -1, -1, -1, -1, -1, -1, 20, -1, 1, -1}, /* 5 - Robat */
+ {-1, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1}, /* 6 - First Coeng */
+ {-1, -1, -1, -1, 12, 13, -1, 10, 16, 17, 1, 14}, /* 7 - First consonant of type 1 after coeng */
+ {-1, -1, -1, -1, 12, 13, -1, -1, 16, 17, 1, 14}, /* 8 - First consonant of type 2 after coeng */
+ {-1, -1, -1, -1, 12, 13, -1, 10, 16, 17, 1, 14}, /* 9 - First consonant or type 3 after ceong */
+ {-1, 11, 11, 11, -1, -1, -1, -1, -1, -1, -1, -1}, /* 10 - Second Coeng (no register shifter before) */
+ {-1, -1, -1, -1, 15, -1, -1, -1, 16, 17, 1, 14}, /* 11 - Second coeng consonant (or ind. vowel) no register shifter before */
+ {-1, -1, -1, -1, -1, 13, -1, -1, 16, -1, -1, -1}, /* 12 - Second ZWNJ before a register shifter */
+ {-1, -1, -1, -1, 15, -1, -1, -1, 16, 17, 1, 14}, /* 13 - Second register shifter */
+ {-1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1}, /* 14 - ZWJ before vowel */
+ {-1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1}, /* 15 - ZWNJ before vowel */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 1, 18}, /* 16 - dependent vowel */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 18}, /* 17 - sign above */
+ {-1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1}, /* 18 - ZWJ after vowel */
+ {-1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 19 - Third coeng */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1}, /* 20 - dependent vowel after a Robat */
+};
+
+
+/* #define KHMER_DEBUG */
+#ifdef KHMER_DEBUG
+#define KHDEBUG qDebug
+#else
+#define KHDEBUG if(0) printf
+#endif
+
+/*
+// Given an input string of characters and a location in which to start looking
+// calculate, using the state table, which one is the last character of the syllable
+// that starts in the starting position.
+*/
+static int khmer_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
+{
+ const HB_UChar16 *uc = s + start;
+ int state = 0;
+ int pos = start;
+ *invalid = FALSE;
+
+ while (pos < end) {
+ KhmerCharClass charClass = getKhmerCharClass(*uc);
+ if (pos == start) {
+ *invalid = (charClass > 0) && ! (charClass & CF_CONSONANT);
+ }
+ state = khmerStateTable[state][charClass & CF_CLASS_MASK];
+
+ KHDEBUG("state[%d]=%d class=%8lx (uc=%4x)", pos - start, state,
+ charClass, *uc );
+
+ if (state < 0) {
+ break;
+ }
+ ++uc;
+ ++pos;
+ }
+ return pos;
+}
+
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature khmer_features[] = {
+ { HB_MAKE_TAG( 'p', 'r', 'e', 'f' ), PreFormProperty },
+ { HB_MAKE_TAG( 'b', 'l', 'w', 'f' ), BelowFormProperty },
+ { HB_MAKE_TAG( 'a', 'b', 'v', 'f' ), AboveFormProperty },
+ { HB_MAKE_TAG( 'p', 's', 't', 'f' ), PostFormProperty },
+ { HB_MAKE_TAG( 'p', 'r', 'e', 's' ), PreSubstProperty },
+ { HB_MAKE_TAG( 'b', 'l', 'w', 's' ), BelowSubstProperty },
+ { HB_MAKE_TAG( 'a', 'b', 'v', 's' ), AboveSubstProperty },
+ { HB_MAKE_TAG( 'p', 's', 't', 's' ), PostSubstProperty },
+ { HB_MAKE_TAG( 'c', 'l', 'i', 'g' ), CligProperty },
+ { 0, 0 }
+};
+#endif
+
+
+static HB_Bool khmer_shape_syllable(HB_Bool openType, HB_ShaperItem *item)
+{
+/* KHDEBUG("syllable from %d len %d, str='%s'", item->from, item->length,
+ item->string->mid(item->from, item->length).toUtf8().data()); */
+
+ int len = 0;
+ int syllableEnd = item->item.pos + item->item.length;
+ unsigned short reordered[16];
+ unsigned char properties[16];
+ enum {
+ AboveForm = 0x01,
+ PreForm = 0x02,
+ PostForm = 0x04,
+ BelowForm = 0x08
+ };
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+ int coengRo;
+ int i;
+
+ /* according to the specs this is the max length one can get
+ ### the real value should be smaller */
+ assert(item->item.length < 13);
+
+ memset(properties, 0, 16*sizeof(unsigned char));
+
+#ifdef KHMER_DEBUG
+ qDebug("original:");
+ for (int i = from; i < syllableEnd; i++) {
+ qDebug(" %d: %4x", i, string[i]);
+ }
+#endif
+
+ /*
+ // write a pre vowel or the pre part of a split vowel first
+ // and look out for coeng + ro. RO is the only vowel of type 2, and
+ // therefore the only one that requires saving space before the base.
+ */
+ coengRo = -1; /* There is no Coeng Ro, if found this value will change */
+ for (i = item->item.pos; i < syllableEnd; i += 1) {
+ KhmerCharClass charClass = getKhmerCharClass(item->string[i]);
+
+ /* if a split vowel, write the pre part. In Khmer the pre part
+ is the same for all split vowels, same glyph as pre vowel C_VOWEL_E */
+ if (charClass & CF_SPLIT_VOWEL) {
+ reordered[len] = C_VOWEL_E;
+ properties[len] = PreForm;
+ ++len;
+ break; /* there can be only one vowel */
+ }
+ /* if a vowel with pos before write it out */
+ if (charClass & CF_POS_BEFORE) {
+ reordered[len] = item->string[i];
+ properties[len] = PreForm;
+ ++len;
+ break; /* there can be only one vowel */
+ }
+ /* look for coeng + ro and remember position
+ works because coeng + ro is always in front of a vowel (if there is a vowel)
+ and because CC_CONSONANT2 is enough to identify it, as it is the only consonant
+ with this flag */
+ if ( (charClass & CF_COENG) && (i + 1 < syllableEnd) &&
+ ( (getKhmerCharClass(item->string[i+1]) & CF_CLASS_MASK) == CC_CONSONANT2) ) {
+ coengRo = i;
+ }
+ }
+
+ /* write coeng + ro if found */
+ if (coengRo > -1) {
+ reordered[len] = C_COENG;
+ properties[len] = PreForm;
+ ++len;
+ reordered[len] = C_RO;
+ properties[len] = PreForm;
+ ++len;
+ }
+
+ /*
+ shall we add a dotted circle?
+ If in the position in which the base should be (first char in the string) there is
+ a character that has the Dotted circle flag (a character that cannot be a base)
+ then write a dotted circle */
+ if (getKhmerCharClass(item->string[item->item.pos]) & CF_DOTTED_CIRCLE) {
+ reordered[len] = C_DOTTED_CIRCLE;
+ ++len;
+ }
+
+ /* copy what is left to the output, skipping before vowels and
+ coeng Ro if they are present */
+ for (i = item->item.pos; i < syllableEnd; i += 1) {
+ HB_UChar16 uc = item->string[i];
+ KhmerCharClass charClass = getKhmerCharClass(uc);
+
+ /* skip a before vowel, it was already processed */
+ if (charClass & CF_POS_BEFORE) {
+ continue;
+ }
+
+ /* skip coeng + ro, it was already processed */
+ if (i == coengRo) {
+ i += 1;
+ continue;
+ }
+
+ switch (charClass & CF_POS_MASK)
+ {
+ case CF_POS_ABOVE :
+ reordered[len] = uc;
+ properties[len] = AboveForm;
+ ++len;
+ break;
+
+ case CF_POS_AFTER :
+ reordered[len] = uc;
+ properties[len] = PostForm;
+ ++len;
+ break;
+
+ case CF_POS_BELOW :
+ reordered[len] = uc;
+ properties[len] = BelowForm;
+ ++len;
+ break;
+
+ default:
+ /* assign the correct flags to a coeng consonant
+ Consonants of type 3 are taged as Post forms and those type 1 as below forms */
+ if ( (charClass & CF_COENG) && i + 1 < syllableEnd ) {
+ unsigned char property = (getKhmerCharClass(item->string[i+1]) & CF_CLASS_MASK) == CC_CONSONANT3 ?
+ PostForm : BelowForm;
+ reordered[len] = uc;
+ properties[len] = property;
+ ++len;
+ i += 1;
+ reordered[len] = item->string[i];
+ properties[len] = property;
+ ++len;
+ break;
+ }
+
+ /* if a shifter is followed by an above vowel change the shifter to below form,
+ an above vowel can have two possible positions i + 1 or i + 3
+ (position i+1 corresponds to unicode 3, position i+3 to Unicode 4)
+ and there is an extra rule for C_VOWEL_AA + C_SIGN_NIKAHIT also for two
+ different positions, right after the shifter or after a vowel (Unicode 4) */
+ if ( (charClass & CF_SHIFTER) && (i + 1 < syllableEnd) ) {
+ if (getKhmerCharClass(item->string[i+1]) & CF_ABOVE_VOWEL ) {
+ reordered[len] = uc;
+ properties[len] = BelowForm;
+ ++len;
+ break;
+ }
+ if (i + 2 < syllableEnd &&
+ (item->string[i+1] == C_VOWEL_AA) &&
+ (item->string[i+2] == C_SIGN_NIKAHIT) )
+ {
+ reordered[len] = uc;
+ properties[len] = BelowForm;
+ ++len;
+ break;
+ }
+ if (i + 3 < syllableEnd && (getKhmerCharClass(item->string[i+3]) & CF_ABOVE_VOWEL) ) {
+ reordered[len] = uc;
+ properties[len] = BelowForm;
+ ++len;
+ break;
+ }
+ if (i + 4 < syllableEnd &&
+ (item->string[i+3] == C_VOWEL_AA) &&
+ (item->string[i+4] == C_SIGN_NIKAHIT) )
+ {
+ reordered[len] = uc;
+ properties[len] = BelowForm;
+ ++len;
+ break;
+ }
+ }
+
+ /* default - any other characters */
+ reordered[len] = uc;
+ ++len;
+ break;
+ } /* switch */
+ } /* for */
+
+ if (!item->font->klass->convertStringToGlyphIndices(item->font,
+ reordered, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2))
+ return FALSE;
+
+
+ KHDEBUG("after shaping: len=%d", len);
+ for (i = 0; i < len; i++) {
+ item->attributes[i].mark = FALSE;
+ item->attributes[i].clusterStart = FALSE;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = FALSE;
+ KHDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]);
+ }
+
+ /* now we have the syllable in the right order, and can start running it through open type. */
+
+#ifndef NO_OPENTYPE
+ if (openType) {
+ hb_uint32 where[16];
+ for (i = 0; i < len; ++i) {
+ where[i] = ~(PreSubstProperty
+ | BelowSubstProperty
+ | AboveSubstProperty
+ | PostSubstProperty
+ | CligProperty
+ | PositioningProperties);
+ if (properties[i] == PreForm)
+ where[i] &= ~PreFormProperty;
+ else if (properties[i] == BelowForm)
+ where[i] &= ~BelowFormProperty;
+ else if (properties[i] == AboveForm)
+ where[i] &= ~AboveFormProperty;
+ else if (properties[i] == PostForm)
+ where[i] &= ~PostFormProperty;
+ }
+
+ HB_OpenTypeShape(item, where);
+ if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
+ return FALSE;
+ } else
+#endif
+ {
+ KHDEBUG("Not using openType");
+ HB_HeuristicPosition(item);
+ }
+
+ item->attributes[0].clusterStart = TRUE;
+ return TRUE;
+}
+
+HB_Bool HB_KhmerShape(HB_ShaperItem *item)
+{
+ HB_Bool openType = FALSE;
+ unsigned short *logClusters = item->log_clusters;
+ int i;
+
+ HB_ShaperItem syllable = *item;
+ int first_glyph = 0;
+
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+
+ assert(item->item.script == HB_Script_Khmer);
+
+#ifndef NO_OPENTYPE
+ openType = HB_SelectScript(item, khmer_features);
+#endif
+
+ KHDEBUG("khmer_shape: from %d length %d", item->item.pos, item->item.length);
+ while (sstart < end) {
+ HB_Bool invalid;
+ int send = khmer_nextSyllableBoundary(item->string, sstart, end, &invalid);
+ KHDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
+ invalid ? "TRUE" : "FALSE");
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!khmer_shape_syllable(openType, &syllable)) {
+ KHDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
+ item->num_glyphs += syllable.num_glyphs;
+ return FALSE;
+ }
+ /* fix logcluster array */
+ KHDEBUG("syllable:");
+ for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i)
+ KHDEBUG(" %d -> glyph %x", i, item->glyphs[i]);
+ KHDEBUG(" logclusters:");
+ for (i = sstart; i < send; ++i) {
+ KHDEBUG(" %d -> glyph %d", i, first_glyph);
+ logClusters[i-item->item.pos] = first_glyph;
+ }
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return TRUE;
+}
+
+void HB_KhmerAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ int end = from + len;
+ const HB_UChar16 *uc = text + from;
+ hb_uint32 i = 0;
+ HB_UNUSED(script);
+ attributes += from;
+ while ( i < len ) {
+ HB_Bool invalid;
+ hb_uint32 boundary = khmer_nextSyllableBoundary( text, from+i, end, &invalid ) - from;
+
+ attributes[i].charStop = TRUE;
+
+ if ( boundary > len-1 ) boundary = len;
+ i++;
+ while ( i < boundary ) {
+ attributes[i].charStop = FALSE;
+ ++uc;
+ ++i;
+ }
+ assert( i == boundary );
+ }
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-myanmar.c b/third_party/harfbuzz/src/harfbuzz-myanmar.c
new file mode 100644
index 0000000..7cd82bb
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-myanmar.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+enum MymrCharClassValues
+{
+ Mymr_CC_RESERVED = 0,
+ Mymr_CC_CONSONANT = 1, /* Consonant of type 1, that has subscript form */
+ Mymr_CC_CONSONANT2 = 2, /* Consonant of type 2, that has no subscript form */
+ Mymr_CC_NGA = 3, /* Consonant NGA */
+ Mymr_CC_YA = 4, /* Consonant YA */
+ Mymr_CC_RA = 5, /* Consonant RA */
+ Mymr_CC_WA = 6, /* Consonant WA */
+ Mymr_CC_HA = 7, /* Consonant HA */
+ Mymr_CC_IND_VOWEL = 8, /* Independent vowel */
+ Mymr_CC_ZERO_WIDTH_NJ_MARK = 9, /* Zero Width non joiner character (0x200C) */
+ Mymr_CC_VIRAMA = 10, /* Subscript consonant combining character */
+ Mymr_CC_PRE_VOWEL = 11, /* Dependent vowel, prebase (Vowel e) */
+ Mymr_CC_BELOW_VOWEL = 12, /* Dependent vowel, prebase (Vowel u, uu) */
+ Mymr_CC_ABOVE_VOWEL = 13, /* Dependent vowel, prebase (Vowel i, ii, ai) */
+ Mymr_CC_POST_VOWEL = 14, /* Dependent vowel, prebase (Vowel aa) */
+ Mymr_CC_SIGN_ABOVE = 15,
+ Mymr_CC_SIGN_BELOW = 16,
+ Mymr_CC_SIGN_AFTER = 17,
+ Mymr_CC_ZERO_WIDTH_J_MARK = 18, /* Zero width joiner character */
+ Mymr_CC_COUNT = 19 /* This is the number of character classes */
+};
+
+enum MymrCharClassFlags
+{
+ Mymr_CF_CLASS_MASK = 0x0000FFFF,
+
+ Mymr_CF_CONSONANT = 0x01000000, /* flag to speed up comparing */
+ Mymr_CF_MEDIAL = 0x02000000, /* flag to speed up comparing */
+ Mymr_CF_IND_VOWEL = 0x04000000, /* flag to speed up comparing */
+ Mymr_CF_DEP_VOWEL = 0x08000000, /* flag to speed up comparing */
+ Mymr_CF_DOTTED_CIRCLE = 0x10000000, /* add a dotted circle if a character with this flag is the first in a syllable */
+ Mymr_CF_VIRAMA = 0x20000000, /* flag to speed up comparing */
+
+ /* position flags */
+ Mymr_CF_POS_BEFORE = 0x00080000,
+ Mymr_CF_POS_BELOW = 0x00040000,
+ Mymr_CF_POS_ABOVE = 0x00020000,
+ Mymr_CF_POS_AFTER = 0x00010000,
+ Mymr_CF_POS_MASK = 0x000f0000,
+
+ Mymr_CF_AFTER_KINZI = 0x00100000
+};
+
+/* Characters that get refrered to by name */
+enum MymrChar
+{
+ Mymr_C_SIGN_ZWNJ = 0x200C,
+ Mymr_C_SIGN_ZWJ = 0x200D,
+ Mymr_C_DOTTED_CIRCLE = 0x25CC,
+ Mymr_C_RA = 0x101B,
+ Mymr_C_YA = 0x101A,
+ Mymr_C_NGA = 0x1004,
+ Mymr_C_VOWEL_E = 0x1031,
+ Mymr_C_VIRAMA = 0x1039
+};
+
+enum
+{
+ Mymr_xx = Mymr_CC_RESERVED,
+ Mymr_c1 = Mymr_CC_CONSONANT | Mymr_CF_CONSONANT | Mymr_CF_POS_BELOW,
+ Mymr_c2 = Mymr_CC_CONSONANT2 | Mymr_CF_CONSONANT,
+ Mymr_ng = Mymr_CC_NGA | Mymr_CF_CONSONANT | Mymr_CF_POS_ABOVE,
+ Mymr_ya = Mymr_CC_YA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_AFTER | Mymr_CF_AFTER_KINZI,
+ Mymr_ra = Mymr_CC_RA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BEFORE,
+ Mymr_wa = Mymr_CC_WA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW,
+ Mymr_ha = Mymr_CC_HA | Mymr_CF_CONSONANT | Mymr_CF_MEDIAL | Mymr_CF_POS_BELOW,
+ Mymr_id = Mymr_CC_IND_VOWEL | Mymr_CF_IND_VOWEL,
+ Mymr_vi = Mymr_CC_VIRAMA | Mymr_CF_VIRAMA | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE,
+ Mymr_dl = Mymr_CC_PRE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BEFORE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
+ Mymr_db = Mymr_CC_BELOW_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
+ Mymr_da = Mymr_CC_ABOVE_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
+ Mymr_dr = Mymr_CC_POST_VOWEL | Mymr_CF_DEP_VOWEL | Mymr_CF_POS_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI,
+ Mymr_sa = Mymr_CC_SIGN_ABOVE | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_ABOVE | Mymr_CF_AFTER_KINZI,
+ Mymr_sb = Mymr_CC_SIGN_BELOW | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_POS_BELOW | Mymr_CF_AFTER_KINZI,
+ Mymr_sp = Mymr_CC_SIGN_AFTER | Mymr_CF_DOTTED_CIRCLE | Mymr_CF_AFTER_KINZI
+};
+
+
+typedef int MymrCharClass;
+
+
+static const MymrCharClass mymrCharClasses[] =
+{
+ Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_ng, Mymr_c1, Mymr_c1, Mymr_c1,
+ Mymr_c1, Mymr_c1, Mymr_c2, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, /* 1000 - 100F */
+ Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1, Mymr_c1,
+ Mymr_c1, Mymr_c1, Mymr_ya, Mymr_ra, Mymr_c1, Mymr_wa, Mymr_c1, Mymr_ha, /* 1010 - 101F */
+ Mymr_c2, Mymr_c2, Mymr_xx, Mymr_id, Mymr_id, Mymr_id, Mymr_id, Mymr_id,
+ Mymr_xx, Mymr_id, Mymr_id, Mymr_xx, Mymr_dr, Mymr_da, Mymr_da, Mymr_db, /* 1020 - 102F */
+ Mymr_db, Mymr_dl, Mymr_da, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_sa, Mymr_sb,
+ Mymr_sp, Mymr_vi, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1030 - 103F */
+ Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx,
+ Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1040 - 104F */
+ Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx,
+ Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, Mymr_xx, /* 1050 - 105F */
+};
+
+static MymrCharClass
+getMyanmarCharClass (HB_UChar16 ch)
+{
+ if (ch == Mymr_C_SIGN_ZWJ)
+ return Mymr_CC_ZERO_WIDTH_J_MARK;
+
+ if (ch == Mymr_C_SIGN_ZWNJ)
+ return Mymr_CC_ZERO_WIDTH_NJ_MARK;
+
+ if (ch < 0x1000 || ch > 0x105f)
+ return Mymr_CC_RESERVED;
+
+ return mymrCharClasses[ch - 0x1000];
+}
+
+static const signed char mymrStateTable[][Mymr_CC_COUNT] =
+{
+/* xx c1, c2 ng ya ra wa ha id zwnj vi dl db da dr sa sb sp zwj */
+ { 1, 4, 4, 2, 4, 4, 4, 4, 24, 1, 27, 17, 18, 19, 20, 21, 1, 1, 4}, /* 0 - ground state */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 1 - exit state (or sp to the right of the syllable) */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 17, 18, 19, 20, 21, -1, -1, 4}, /* 2 - NGA */
+ {-1, 4, 4, 4, 4, 4, 4, 4, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 3 - Virama after NGA */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 17, 18, 19, 20, 21, 1, 1, -1}, /* 4 - Base consonant */
+ {-2, 6, -2, -2, 7, 8, 9, 10, -2, 23, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 5 - First virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, 17, 18, 19, 20, 21, -1, -1, -1}, /* 6 - c1 after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 7 - ya after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 8 - ra after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, -1, -1}, /* 9 - wa after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 10 - ha after virama */
+ {-1, -1, -1, -1, 7, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 11 - Virama after NGA+zwj */
+ {-2, -2, -2, -2, -2, -2, 13, 14, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 12 - Second virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, 17, 18, 19, 20, 21, -1, -1, -1}, /* 13 - wa after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 14 - ha after virama */
+ {-2, -2, -2, -2, -2, -2, -2, 16, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 15 - Third virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, -1, -1, -1}, /* 16 - ha after virama */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, 21, 1, 1, -1}, /* 17 - dl, Dependent vowel e */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, 21, 1, 1, -1}, /* 18 - db, Dependent vowel u,uu */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1}, /* 19 - da, Dependent vowel i,ii,ai */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, 1, 1, -1}, /* 20 - dr, Dependent vowel aa */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 21 - sa, Sign anusvara */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 22 - atha */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1}, /* 23 - zwnj for atha */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1}, /* 24 - Independent vowel */
+ {-2, -2, -2, -2, 26, 26, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2}, /* 25 - Virama after subscript consonant */
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 17, 18, 19, 20, 21, -1, 1, -1}, /* 26 - ra/ya after subscript consonant + virama */
+ {-1, 6, -1, -1, 7, 8, 9, 10, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 27 - Virama after ground state */
+/* exit state -2 is for invalid order of medials and combination of invalids
+ with virama where virama should treat as start of next syllable
+ */
+};
+
+
+
+/*#define MYANMAR_DEBUG */
+#ifdef MYANMAR_DEBUG
+#define MMDEBUG qDebug
+#else
+#define MMDEBUG if(0) printf
+#endif
+
+/*
+// Given an input string of characters and a location in which to start looking
+// calculate, using the state table, which one is the last character of the syllable
+// that starts in the starting position.
+*/
+static int myanmar_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
+{
+ const HB_UChar16 *uc = s + start;
+ int state = 0;
+ int pos = start;
+ *invalid = FALSE;
+
+ while (pos < end) {
+ MymrCharClass charClass = getMyanmarCharClass(*uc);
+ state = mymrStateTable[state][charClass & Mymr_CF_CLASS_MASK];
+ if (pos == start)
+ *invalid = (HB_Bool)(charClass & Mymr_CF_DOTTED_CIRCLE);
+
+ MMDEBUG("state[%d]=%d class=%8x (uc=%4x)", pos - start, state, charClass, *uc);
+
+ if (state < 0) {
+ if (state < -1)
+ --pos;
+ break;
+ }
+ ++uc;
+ ++pos;
+ }
+ return pos;
+}
+
+#ifndef NO_OPENTYPE
+/* ###### might have to change order of above and below forms and substitutions,
+ but according to Unicode below comes before above */
+static const HB_OpenTypeFeature myanmar_features[] = {
+ { HB_MAKE_TAG('p', 'r', 'e', 'f'), PreFormProperty },
+ { HB_MAKE_TAG('b', 'l', 'w', 'f'), BelowFormProperty },
+ { HB_MAKE_TAG('a', 'b', 'v', 'f'), AboveFormProperty },
+ { HB_MAKE_TAG('p', 's', 't', 'f'), PostFormProperty },
+ { HB_MAKE_TAG('p', 'r', 'e', 's'), PreSubstProperty },
+ { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
+ { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
+ { HB_MAKE_TAG('p', 's', 't', 's'), PostSubstProperty },
+ { HB_MAKE_TAG('r', 'l', 'i', 'g'), CligProperty }, /* Myanmar1 uses this instead of the other features */
+ { 0, 0 }
+};
+#endif
+
+
+/*
+// Visual order before shaping should be:
+//
+// [Vowel Mark E]
+// [Virama + Medial Ra]
+// [Base]
+// [Virama + Consonant]
+// [Nga + Virama] (Kinzi) ### should probably come before post forms (medial ya)
+// [Vowels]
+// [Marks]
+//
+// This means that we can keep the logical order apart from having to
+// move the pre vowel, medial ra and kinzi
+*/
+
+static HB_Bool myanmar_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid)
+{
+ /*
+// MMDEBUG("\nsyllable from %d len %d, str='%s'", item->item.pos, item->item.length,
+// item->string->mid(item->from, item->length).toUtf8().data());
+ */
+
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+ const HB_UChar16 *uc = item->string + item->item.pos;
+ int vowel_e = -1;
+ int kinzi = -1;
+ int medial_ra = -1;
+ int base = -1;
+ int i;
+ int len = 0;
+ unsigned short reordered[32];
+ unsigned char properties[32];
+ enum {
+ AboveForm = 0x01,
+ PreForm = 0x02,
+ PostForm = 0x04,
+ BelowForm = 0x08
+ };
+ HB_Bool lastWasVirama = FALSE;
+ int basePos = -1;
+
+ memset(properties, 0, 32*sizeof(unsigned char));
+
+ /* according to the table the max length of a syllable should be around 14 chars */
+ assert(item->item.length < 32);
+
+#ifdef MYANMAR_DEBUG
+ printf("original:");
+ for (i = 0; i < (int)item->item.length; i++) {
+ printf(" %d: %4x", i, uc[i]);
+ }
+#endif
+ for (i = 0; i < (int)item->item.length; ++i) {
+ HB_UChar16 chr = uc[i];
+
+ if (chr == Mymr_C_VOWEL_E) {
+ vowel_e = i;
+ continue;
+ }
+ if (i == 0
+ && chr == Mymr_C_NGA
+ && i + 2 < (int)item->item.length
+ && uc[i+1] == Mymr_C_VIRAMA) {
+ int mc = getMyanmarCharClass(uc[i+2]);
+ /*MMDEBUG("maybe kinzi: mc=%x", mc);*/
+ if ((mc & Mymr_CF_CONSONANT) == Mymr_CF_CONSONANT) {
+ kinzi = i;
+ continue;
+ }
+ }
+ if (base >= 0
+ && chr == Mymr_C_VIRAMA
+ && i + 1 < (int)item->item.length
+ && uc[i+1] == Mymr_C_RA) {
+ medial_ra = i;
+ continue;
+ }
+ if (base < 0)
+ base = i;
+ }
+
+ MMDEBUG("\n base=%d, vowel_e=%d, kinzi=%d, medial_ra=%d", base, vowel_e, kinzi, medial_ra);
+ /* write vowel_e if found */
+ if (vowel_e >= 0) {
+ reordered[0] = Mymr_C_VOWEL_E;
+ len = 1;
+ }
+ /* write medial_ra */
+ if (medial_ra >= 0) {
+ reordered[len] = Mymr_C_VIRAMA;
+ reordered[len+1] = Mymr_C_RA;
+ properties[len] = PreForm;
+ properties[len+1] = PreForm;
+ len += 2;
+ }
+
+ /* shall we add a dotted circle?
+ If in the position in which the base should be (first char in the string) there is
+ a character that has the Dotted circle flag (a character that cannot be a base)
+ then write a dotted circle */
+ if (invalid) {
+ reordered[len] = C_DOTTED_CIRCLE;
+ ++len;
+ }
+
+ /* copy the rest of the syllable to the output, inserting the kinzi
+ at the correct place */
+ for (i = 0; i < (int)item->item.length; ++i) {
+ hb_uint16 chr = uc[i];
+ MymrCharClass cc;
+ if (i == vowel_e)
+ continue;
+ if (i == medial_ra || i == kinzi) {
+ ++i;
+ continue;
+ }
+
+ cc = getMyanmarCharClass(uc[i]);
+ if (kinzi >= 0 && i > base && (cc & Mymr_CF_AFTER_KINZI)) {
+ reordered[len] = Mymr_C_NGA;
+ reordered[len+1] = Mymr_C_VIRAMA;
+ properties[len-1] = AboveForm;
+ properties[len] = AboveForm;
+ len += 2;
+ kinzi = -1;
+ }
+
+ if (lastWasVirama) {
+ int prop = 0;
+ switch(cc & Mymr_CF_POS_MASK) {
+ case Mymr_CF_POS_BEFORE:
+ prop = PreForm;
+ break;
+ case Mymr_CF_POS_BELOW:
+ prop = BelowForm;
+ break;
+ case Mymr_CF_POS_ABOVE:
+ prop = AboveForm;
+ break;
+ case Mymr_CF_POS_AFTER:
+ prop = PostForm;
+ break;
+ default:
+ break;
+ }
+ properties[len-1] = prop;
+ properties[len] = prop;
+ if(basePos >= 0 && basePos == len-2)
+ properties[len-2] = prop;
+ }
+ lastWasVirama = (chr == Mymr_C_VIRAMA);
+ if(i == base)
+ basePos = len;
+
+ if ((chr != Mymr_C_SIGN_ZWNJ && chr != Mymr_C_SIGN_ZWJ) || !len) {
+ reordered[len] = chr;
+ ++len;
+ }
+ }
+ if (kinzi >= 0) {
+ reordered[len] = Mymr_C_NGA;
+ reordered[len+1] = Mymr_C_VIRAMA;
+ properties[len] = AboveForm;
+ properties[len+1] = AboveForm;
+ len += 2;
+ }
+
+ if (!item->font->klass->convertStringToGlyphIndices(item->font,
+ reordered, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2))
+ return FALSE;
+
+ MMDEBUG("after shaping: len=%d", len);
+ for (i = 0; i < len; i++) {
+ item->attributes[i].mark = FALSE;
+ item->attributes[i].clusterStart = FALSE;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = FALSE;
+ MMDEBUG(" %d: %4x property=%x", i, reordered[i], properties[i]);
+ }
+
+ /* now we have the syllable in the right order, and can start running it through open type. */
+
+#ifndef NO_OPENTYPE
+ if (openType) {
+ unsigned short logClusters[32];
+ hb_uint32 where[32];
+
+ for (i = 0; i < len; ++i)
+ logClusters[i] = i;
+
+ for (i = 0; i < len; ++i) {
+ where[i] = ~(PreSubstProperty
+ | BelowSubstProperty
+ | AboveSubstProperty
+ | PostSubstProperty
+ | CligProperty
+ | PositioningProperties);
+ if (properties[i] & PreForm)
+ where[i] &= ~PreFormProperty;
+ if (properties[i] & BelowForm)
+ where[i] &= ~BelowFormProperty;
+ if (properties[i] & AboveForm)
+ where[i] &= ~AboveFormProperty;
+ if (properties[i] & PostForm)
+ where[i] &= ~PostFormProperty;
+ }
+
+ HB_OpenTypeShape(item, where);
+ if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
+ return FALSE;
+ } else
+#endif
+ {
+ MMDEBUG("Not using openType");
+ HB_HeuristicPosition(item);
+ }
+
+ item->attributes[0].clusterStart = TRUE;
+ return TRUE;
+}
+
+HB_Bool HB_MyanmarShape(HB_ShaperItem *item)
+{
+ HB_Bool openType = FALSE;
+ unsigned short *logClusters = item->log_clusters;
+
+ HB_ShaperItem syllable = *item;
+ int first_glyph = 0;
+
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+ int i = 0;
+
+ assert(item->item.script == HB_Script_Myanmar);
+#ifndef NO_OPENTYPE
+ openType = HB_SelectScript(item, myanmar_features);
+#endif
+
+ MMDEBUG("myanmar_shape: from %d length %d", item->item.pos, item->item.length);
+ while (sstart < end) {
+ HB_Bool invalid;
+ int send = myanmar_nextSyllableBoundary(item->string, sstart, end, &invalid);
+ MMDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
+ invalid ? "TRUE" : "FALSE");
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!myanmar_shape_syllable(openType, &syllable, invalid)) {
+ MMDEBUG("syllable shaping failed, syllable requests %d glyphs", syllable.num_glyphs);
+ item->num_glyphs += syllable.num_glyphs;
+ return FALSE;
+ }
+
+ /* fix logcluster array */
+ MMDEBUG("syllable:");
+ for (i = first_glyph; i < first_glyph + (int)syllable.num_glyphs; ++i)
+ MMDEBUG(" %d -> glyph %x", i, item->glyphs[i]);
+ MMDEBUG(" logclusters:");
+ for (i = sstart; i < send; ++i) {
+ MMDEBUG(" %d -> glyph %d", i, first_glyph);
+ logClusters[i-item->item.pos] = first_glyph;
+ }
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return TRUE;
+}
+
+void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ int end = from + len;
+ const HB_UChar16 *uc = text + from;
+ hb_uint32 i = 0;
+ HB_UNUSED(script);
+ attributes += from;
+ while (i < len) {
+ HB_Bool invalid;
+ hb_uint32 boundary = myanmar_nextSyllableBoundary(text, from+i, end, &invalid) - from;
+
+ attributes[i].charStop = TRUE;
+ if (i)
+ attributes[i-1].lineBreakType = HB_Break;
+
+ if (boundary > len-1)
+ boundary = len;
+ i++;
+ while (i < boundary) {
+ attributes[i].charStop = FALSE;
+ ++uc;
+ ++i;
+ }
+ assert(i == boundary);
+ }
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-open-private.h b/third_party/harfbuzz/src/harfbuzz-open-private.h
new file mode 100644
index 0000000..73dd383
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-open-private.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_OPEN_PRIVATE_H
+#define HARFBUZZ_OPEN_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-open.h"
+#include "harfbuzz-gsub-private.h"
+#include "harfbuzz-gpos-private.h"
+
+HB_BEGIN_HEADER
+
+
+struct HB_SubTable_
+{
+ union
+ {
+ HB_GSUB_SubTable gsub;
+ HB_GPOS_SubTable gpos;
+ } st;
+};
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
+ HB_Stream input );
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
+ HB_Stream input );
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_LookupList( HB_LookupList* ll,
+ HB_Stream input,
+ HB_Type type );
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Coverage( HB_Coverage* c,
+ HB_Stream input );
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream input );
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_UInt class_offset,
+ HB_UInt base_offset,
+ HB_Stream input );
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Device( HB_Device* d,
+ HB_Stream input );
+
+HB_INTERNAL void _HB_OPEN_Free_ScriptList( HB_ScriptList* sl );
+HB_INTERNAL void _HB_OPEN_Free_FeatureList( HB_FeatureList* fl );
+HB_INTERNAL void _HB_OPEN_Free_LookupList( HB_LookupList* ll,
+ HB_Type type );
+
+HB_INTERNAL void _HB_OPEN_Free_Coverage( HB_Coverage* c );
+HB_INTERNAL void _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd );
+HB_INTERNAL void _HB_OPEN_Free_Device( HB_Device* d );
+
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Coverage_Index( HB_Coverage* c,
+ HB_UShort glyphID,
+ HB_UShort* index );
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Class( HB_ClassDefinition* cd,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index );
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Device( HB_Device* d,
+ HB_UShort size,
+ HB_Short* value );
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_OPEN_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-open.c b/third_party/harfbuzz/src/harfbuzz-open.c
new file mode 100644
index 0000000..cde5465
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-open.c
@@ -0,0 +1,1414 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-open-private.h"
+
+
+/***************************
+ * Script related functions
+ ***************************/
+
+
+/* LangSys */
+
+static HB_Error Load_LangSys( HB_LangSys* ls,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UShort n, count;
+ HB_UShort* fi;
+
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ ls->LookupOrderOffset = GET_UShort(); /* should be 0 */
+ ls->ReqFeatureIndex = GET_UShort();
+ count = ls->FeatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ls->FeatureIndex = NULL;
+
+ if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
+ return error;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( ls->FeatureIndex );
+ return error;
+ }
+
+ fi = ls->FeatureIndex;
+
+ for ( n = 0; n < count; n++ )
+ fi[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_LangSys( HB_LangSys* ls )
+{
+ FREE( ls->FeatureIndex );
+}
+
+
+/* Script */
+
+static HB_Error Load_Script( HB_ScriptTable* s,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_LangSysRecord* lsr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ if ( new_offset != base_offset ) /* not a NULL offset */
+ {
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LangSys( &s->DefaultLangSys,
+ stream ) ) != HB_Err_Ok )
+ return error;
+ (void)FILE_Seek( cur_offset );
+ }
+ else
+ {
+ /* we create a DefaultLangSys table with no entries */
+
+ s->DefaultLangSys.LookupOrderOffset = 0;
+ s->DefaultLangSys.ReqFeatureIndex = 0xFFFF;
+ s->DefaultLangSys.FeatureCount = 0;
+ s->DefaultLangSys.FeatureIndex = NULL;
+ }
+
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail2;
+
+ count = s->LangSysCount = GET_UShort();
+
+ /* safety check; otherwise the official handling of TrueType Open
+ fonts won't work */
+
+ if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
+ {
+ error = HB_Err_Not_Covered;
+ goto Fail2;
+ }
+
+ FORGET_Frame();
+
+ s->LangSysRecord = NULL;
+
+ if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
+ goto Fail2;
+
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail1;
+
+ lsr[n].LangSysTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_LangSys( &lsr[m].LangSys );
+
+ FREE( s->LangSysRecord );
+
+Fail2:
+ Free_LangSys( &s->DefaultLangSys );
+ return error;
+}
+
+
+static void Free_Script( HB_ScriptTable* s )
+{
+ HB_UShort n, count;
+
+ HB_LangSysRecord* lsr;
+
+
+ Free_LangSys( &s->DefaultLangSys );
+
+ if ( s->LangSysRecord )
+ {
+ count = s->LangSysCount;
+ lsr = s->LangSysRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_LangSys( &lsr[n].LangSys );
+
+ FREE( lsr );
+ }
+}
+
+
+/* ScriptList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, script_count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_ScriptRecord* sr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ script_count = GET_UShort();
+
+ FORGET_Frame();
+
+ sl->ScriptRecord = NULL;
+
+ if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
+ return error;
+
+ sr = sl->ScriptRecord;
+
+ sl->ScriptCount= 0;
+ for ( n = 0; n < script_count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail;
+
+ sr[sl->ScriptCount].ScriptTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+
+ if ( FILE_Seek( new_offset ) )
+ goto Fail;
+
+ error = Load_Script( &sr[sl->ScriptCount].Script, stream );
+ if ( error == HB_Err_Ok )
+ sl->ScriptCount += 1;
+ else if ( error != HB_Err_Not_Covered )
+ goto Fail;
+
+ (void)FILE_Seek( cur_offset );
+ }
+
+ /* Empty tables are harmless and generated by fontforge.
+ * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
+ */
+#if 0
+ if ( sl->ScriptCount == 0 )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+#endif
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( n = 0; n < sl->ScriptCount; n++ )
+ Free_Script( &sr[n].Script );
+
+ FREE( sl->ScriptRecord );
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
+{
+ HB_UShort n, count;
+
+ HB_ScriptRecord* sr;
+
+
+ if ( sl->ScriptRecord )
+ {
+ count = sl->ScriptCount;
+ sr = sl->ScriptRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_Script( &sr[n].Script );
+
+ FREE( sr );
+ }
+}
+
+
+
+/*********************************
+ * Feature List related functions
+ *********************************/
+
+
+/* Feature */
+
+static HB_Error Load_Feature( HB_Feature* f,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* lli;
+
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ f->FeatureParams = GET_UShort(); /* should be 0 */
+ count = f->LookupListCount = GET_UShort();
+
+ FORGET_Frame();
+
+ f->LookupListIndex = NULL;
+
+ if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
+ return error;
+
+ lli = f->LookupListIndex;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( f->LookupListIndex );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ lli[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Feature( HB_Feature* f )
+{
+ FREE( f->LookupListIndex );
+}
+
+
+/* FeatureList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_FeatureRecord* fr;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = fl->FeatureCount = GET_UShort();
+
+ FORGET_Frame();
+
+ fl->FeatureRecord = NULL;
+
+ if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
+ return error;
+ if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
+ goto Fail2;
+
+ fl->ApplyCount = 0;
+
+ fr = fl->FeatureRecord;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 6L ) )
+ goto Fail1;
+
+ fr[n].FeatureTag = GET_ULong();
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ for ( m = 0; m < n; m++ )
+ Free_Feature( &fr[m].Feature );
+
+ FREE( fl->ApplyOrder );
+
+Fail2:
+ FREE( fl->FeatureRecord );
+
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_FeatureList( HB_FeatureList* fl )
+{
+ HB_UShort n, count;
+
+ HB_FeatureRecord* fr;
+
+
+ if ( fl->FeatureRecord )
+ {
+ count = fl->FeatureCount;
+ fr = fl->FeatureRecord;
+
+ for ( n = 0; n < count; n++ )
+ Free_Feature( &fr[n].Feature );
+
+ FREE( fr );
+ }
+
+ FREE( fl->ApplyOrder );
+}
+
+
+
+/********************************
+ * Lookup List related functions
+ ********************************/
+
+/* the subroutines of the following two functions are defined in
+ ftxgsub.c and ftxgpos.c respectively */
+
+
+/* SubTable */
+
+static HB_Error Load_SubTable( HB_SubTable* st,
+ HB_Stream stream,
+ HB_Type table_type,
+ HB_UShort lookup_type )
+{
+ if ( table_type == HB_Type_GSUB )
+ return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type );
+ else
+ return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type );
+}
+
+
+static void Free_SubTable( HB_SubTable* st,
+ HB_Type table_type,
+ HB_UShort lookup_type )
+{
+ if ( table_type == HB_Type_GSUB )
+ _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type );
+ else
+ _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type );
+}
+
+
+/* Lookup */
+
+static HB_Error Load_Lookup( HB_Lookup* l,
+ HB_Stream stream,
+ HB_Type type )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_SubTable* st;
+
+ HB_Bool is_extension = FALSE;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ l->LookupType = GET_UShort();
+ l->LookupFlag = GET_UShort();
+ count = l->SubTableCount = GET_UShort();
+
+ FORGET_Frame();
+
+ l->SubTable = NULL;
+
+ if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
+ return error;
+
+ st = l->SubTable;
+
+ if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) ||
+ ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) )
+ is_extension = TRUE;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+
+ if ( is_extension )
+ {
+ if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
+ goto Fail;
+
+ if (GET_UShort() != 1) /* format should be 1 */
+ goto Fail;
+
+ l->LookupType = GET_UShort();
+ new_offset += GET_ULong();
+
+ FORGET_Frame();
+ }
+
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_SubTable( &st[n], stream,
+ type, l->LookupType ) ) != HB_Err_Ok )
+ goto Fail;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail:
+ for ( m = 0; m < n; m++ )
+ Free_SubTable( &st[m], type, l->LookupType );
+
+ FREE( l->SubTable );
+ return error;
+}
+
+
+static void Free_Lookup( HB_Lookup* l,
+ HB_Type type)
+{
+ HB_UShort n, count;
+
+ HB_SubTable* st;
+
+
+ if ( l->SubTable )
+ {
+ count = l->SubTableCount;
+ st = l->SubTable;
+
+ for ( n = 0; n < count; n++ )
+ Free_SubTable( &st[n], type, l->LookupType );
+
+ FREE( st );
+ }
+}
+
+
+/* LookupList */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_LookupList( HB_LookupList* ll,
+ HB_Stream stream,
+ HB_Type type )
+{
+ HB_Error error;
+
+ HB_UShort n, m, count;
+ HB_UInt cur_offset, new_offset, base_offset;
+
+ HB_Lookup* l;
+
+
+ base_offset = FILE_Pos();
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = ll->LookupCount = GET_UShort();
+
+ FORGET_Frame();
+
+ ll->Lookup = NULL;
+
+ if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
+ return error;
+ if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
+ goto Fail2;
+
+ l = ll->Lookup;
+
+ for ( n = 0; n < count; n++ )
+ {
+ if ( ACCESS_Frame( 2L ) )
+ goto Fail1;
+
+ new_offset = GET_UShort() + base_offset;
+
+ FORGET_Frame();
+
+ cur_offset = FILE_Pos();
+ if ( FILE_Seek( new_offset ) ||
+ ( error = Load_Lookup( &l[n], stream, type ) ) != HB_Err_Ok )
+ goto Fail1;
+ (void)FILE_Seek( cur_offset );
+ }
+
+ return HB_Err_Ok;
+
+Fail1:
+ FREE( ll->Properties );
+
+ for ( m = 0; m < n; m++ )
+ Free_Lookup( &l[m], type );
+
+Fail2:
+ FREE( ll->Lookup );
+ return error;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_LookupList( HB_LookupList* ll,
+ HB_Type type )
+{
+ HB_UShort n, count;
+
+ HB_Lookup* l;
+
+
+ FREE( ll->Properties );
+
+ if ( ll->Lookup )
+ {
+ count = ll->LookupCount;
+ l = ll->Lookup;
+
+ for ( n = 0; n < count; n++ )
+ Free_Lookup( &l[n], type );
+
+ FREE( l );
+ }
+}
+
+
+
+/*****************************
+ * Coverage related functions
+ *****************************/
+
+
+/* CoverageFormat1 */
+
+static HB_Error Load_Coverage1( HB_CoverageFormat1* cf1,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* ga;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cf1->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cf1->GlyphArray = NULL;
+
+ if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
+ return error;
+
+ ga = cf1->GlyphArray;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( cf1->GlyphArray );
+ return error;
+ }
+
+ for ( n = 0; n < count; n++ )
+ ga[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+static void Free_Coverage1( HB_CoverageFormat1* cf1)
+{
+ FREE( cf1->GlyphArray );
+}
+
+
+/* CoverageFormat2 */
+
+static HB_Error Load_Coverage2( HB_CoverageFormat2* cf2,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_RangeRecord* rr;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = cf2->RangeCount = GET_UShort();
+
+ FORGET_Frame();
+
+ cf2->RangeRecord = NULL;
+
+ if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
+ return error;
+
+ rr = cf2->RangeRecord;
+
+ if ( ACCESS_Frame( count * 6L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ rr[n].Start = GET_UShort();
+ rr[n].End = GET_UShort();
+ rr[n].StartCoverageIndex = GET_UShort();
+
+ /* sanity check; we are limited to 16bit integers */
+ if ( rr[n].Start > rr[n].End ||
+ ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
+ 0x10000L )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( cf2->RangeRecord );
+ return error;
+}
+
+
+static void Free_Coverage2( HB_CoverageFormat2* cf2 )
+{
+ FREE( cf2->RangeRecord );
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Coverage( HB_Coverage* c,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ c->CoverageFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( c->CoverageFormat )
+ {
+ case 1: return Load_Coverage1( &c->cf.cf1, stream );
+ case 2: return Load_Coverage2( &c->cf.cf2, stream );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_Coverage( HB_Coverage* c )
+{
+ switch ( c->CoverageFormat )
+ {
+ case 1: Free_Coverage1( &c->cf.cf1 ); break;
+ case 2: Free_Coverage2( &c->cf.cf2 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Coverage_Index1( HB_CoverageFormat1* cf1,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_UShort* array = cf1->GlyphArray;
+
+
+ /* binary search */
+
+ if ( cf1->GlyphCount == 0 )
+ return HB_Err_Not_Covered;
+
+ new_min = 0;
+ new_max = cf1->GlyphCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID == array[middle] )
+ {
+ *index = middle;
+ return HB_Err_Ok;
+ }
+ else if ( glyphID < array[middle] )
+ {
+ if ( middle == min )
+ break;
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ break;
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ return HB_Err_Not_Covered;
+}
+
+
+static HB_Error Coverage_Index2( HB_CoverageFormat2* cf2,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_RangeRecord* rr = cf2->RangeRecord;
+
+
+ /* binary search */
+
+ if ( cf2->RangeCount == 0 )
+ return HB_Err_Not_Covered;
+
+ new_min = 0;
+ new_max = cf2->RangeCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
+ {
+ *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
+ return HB_Err_Ok;
+ }
+ else if ( glyphID < rr[middle].Start )
+ {
+ if ( middle == min )
+ break;
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ break;
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ return HB_Err_Not_Covered;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Coverage_Index( HB_Coverage* c,
+ HB_UShort glyphID,
+ HB_UShort* index )
+{
+ switch ( c->CoverageFormat )
+ {
+ case 1: return Coverage_Index1( &c->cf.cf1, glyphID, index );
+ case 2: return Coverage_Index2( &c->cf.cf2, glyphID, index );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+
+/*************************************
+ * Class Definition related functions
+ *************************************/
+
+
+/* ClassDefFormat1 */
+
+static HB_Error Load_ClassDef1( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* cva;
+
+ HB_ClassDefFormat1* cdf1;
+
+
+ cdf1 = &cd->cd.cd1;
+
+ if ( ACCESS_Frame( 4L ) )
+ return error;
+
+ cdf1->StartGlyph = GET_UShort();
+ count = cdf1->GlyphCount = GET_UShort();
+
+ FORGET_Frame();
+
+ /* sanity check; we are limited to 16bit integers */
+
+ if ( cdf1->StartGlyph + (long)count >= 0x10000L )
+ return ERR(HB_Err_Invalid_SubTable);
+
+ cdf1->ClassValueArray = NULL;
+
+ if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
+ return error;
+
+ cva = cdf1->ClassValueArray;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ cva[n] = GET_UShort();
+ if ( cva[n] >= limit )
+ {
+ error = ERR(HB_Err_Invalid_SubTable);
+ goto Fail;
+ }
+ }
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( cva );
+
+ return error;
+}
+
+
+static void Free_ClassDef1( HB_ClassDefFormat1* cdf1 )
+{
+ FREE( cdf1->ClassValueArray );
+}
+
+
+/* ClassDefFormat2 */
+
+static HB_Error Load_ClassDef2( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_ClassRangeRecord* crr;
+
+ HB_ClassDefFormat2* cdf2;
+
+
+ cdf2 = &cd->cd.cd2;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ count = GET_UShort();
+ cdf2->ClassRangeCount = 0; /* zero for now. we fill with the number of good entries later */
+
+ FORGET_Frame();
+
+ cdf2->ClassRangeRecord = NULL;
+
+ if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
+ return error;
+
+ crr = cdf2->ClassRangeRecord;
+
+ if ( ACCESS_Frame( count * 6L ) )
+ goto Fail;
+
+ for ( n = 0; n < count; n++ )
+ {
+ crr[n].Start = GET_UShort();
+ crr[n].End = GET_UShort();
+ crr[n].Class = GET_UShort();
+
+ /* sanity check */
+
+ if ( crr[n].Start > crr[n].End ||
+ crr[n].Class >= limit )
+ {
+ /* XXX
+ * Corrupt entry. Skip it.
+ * This is hit by Nafees Nastaliq font for example
+ */
+ n--;
+ count--;
+ }
+ }
+
+ FORGET_Frame();
+
+ cdf2->ClassRangeCount = count;
+
+ return HB_Err_Ok;
+
+Fail:
+ FREE( crr );
+
+ return error;
+}
+
+
+static void Free_ClassDef2( HB_ClassDefFormat2* cdf2 )
+{
+ FREE( cdf2->ClassRangeRecord );
+}
+
+
+/* ClassDefinition */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+
+ cd->ClassFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ switch ( cd->ClassFormat )
+ {
+ case 1: error = Load_ClassDef1( cd, limit, stream ); break;
+ case 2: error = Load_ClassDef2( cd, limit, stream ); break;
+ default: error = ERR(HB_Err_Invalid_SubTable_Format); break;
+ }
+
+ if ( error )
+ return error;
+
+ cd->loaded = TRUE;
+
+ return HB_Err_Ok;
+}
+
+
+static HB_Error
+_HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition* cd )
+{
+ HB_Error error;
+
+ cd->ClassFormat = 1; /* Meaningless */
+
+ if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
+ return error;
+
+ return HB_Err_Ok;
+}
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
+ HB_UShort limit,
+ HB_UInt class_offset,
+ HB_UInt base_offset,
+ HB_Stream stream )
+{
+ HB_Error error;
+ HB_UInt cur_offset;
+
+ cur_offset = FILE_Pos();
+
+ if ( class_offset )
+ {
+ if ( !FILE_Seek( class_offset + base_offset ) )
+ error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
+ }
+ else
+ error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
+
+ if (error == HB_Err_Ok)
+ (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
+
+ return error;
+}
+
+HB_INTERNAL void
+_HB_OPEN_Free_ClassDefinition( HB_ClassDefinition* cd )
+{
+ if ( !cd->loaded )
+ return;
+
+ switch ( cd->ClassFormat )
+ {
+ case 1: Free_ClassDef1( &cd->cd.cd1 ); break;
+ case 2: Free_ClassDef2( &cd->cd.cd2 ); break;
+ default: break;
+ }
+}
+
+
+static HB_Error Get_Class1( HB_ClassDefFormat1* cdf1,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ HB_UShort* cva = cdf1->ClassValueArray;
+
+
+ if ( index )
+ *index = 0;
+
+ if ( glyphID >= cdf1->StartGlyph &&
+ glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
+ {
+ *klass = cva[glyphID - cdf1->StartGlyph];
+ return HB_Err_Ok;
+ }
+ else
+ {
+ *klass = 0;
+ return HB_Err_Not_Covered;
+ }
+}
+
+
+/* we need the index value of the last searched class range record
+ in case of failure for constructed GDEF tables */
+
+static HB_Error Get_Class2( HB_ClassDefFormat2* cdf2,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ HB_Error error = HB_Err_Ok;
+ HB_UShort min, max, new_min, new_max, middle;
+
+ HB_ClassRangeRecord* crr = cdf2->ClassRangeRecord;
+
+
+ /* binary search */
+
+ if ( cdf2->ClassRangeCount == 0 )
+ {
+ *klass = 0;
+ if ( index )
+ *index = 0;
+
+ return HB_Err_Not_Covered;
+ }
+
+ new_min = 0;
+ new_max = cdf2->ClassRangeCount - 1;
+
+ do
+ {
+ min = new_min;
+ max = new_max;
+
+ /* we use (min + max) / 2 = max - (max - min) / 2 to avoid
+ overflow and rounding errors */
+
+ middle = max - ( ( max - min ) >> 1 );
+
+ if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
+ {
+ *klass = crr[middle].Class;
+ error = HB_Err_Ok;
+ break;
+ }
+ else if ( glyphID < crr[middle].Start )
+ {
+ if ( middle == min )
+ {
+ *klass = 0;
+ error = HB_Err_Not_Covered;
+ break;
+ }
+ new_max = middle - 1;
+ }
+ else
+ {
+ if ( middle == max )
+ {
+ *klass = 0;
+ error = HB_Err_Not_Covered;
+ break;
+ }
+ new_min = middle + 1;
+ }
+ } while ( min < max );
+
+ if ( index )
+ *index = middle;
+
+ return error;
+}
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Class( HB_ClassDefinition* cd,
+ HB_UShort glyphID,
+ HB_UShort* klass,
+ HB_UShort* index )
+{
+ switch ( cd->ClassFormat )
+ {
+ case 1: return Get_Class1( &cd->cd.cd1, glyphID, klass, index );
+ case 2: return Get_Class2( &cd->cd.cd2, glyphID, klass, index );
+ default: return ERR(HB_Err_Invalid_SubTable_Format);
+ }
+
+ return HB_Err_Ok; /* never reached */
+}
+
+
+
+/***************************
+ * Device related functions
+ ***************************/
+
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Load_Device( HB_Device* d,
+ HB_Stream stream )
+{
+ HB_Error error;
+
+ HB_UShort n, count;
+
+ HB_UShort* dv;
+
+
+ if ( ACCESS_Frame( 6L ) )
+ return error;
+
+ d->StartSize = GET_UShort();
+ d->EndSize = GET_UShort();
+ d->DeltaFormat = GET_UShort();
+
+ FORGET_Frame();
+
+ d->DeltaValue = NULL;
+
+ if ( d->StartSize > d->EndSize ||
+ d->DeltaFormat == 0 || d->DeltaFormat > 3 )
+ {
+ /* XXX
+ * I've seen fontforge generate DeltaFormat == 0.
+ * Just return Ok and let the NULL DeltaValue disable
+ * this table.
+ */
+ return HB_Err_Ok;
+ }
+
+ count = ( ( d->EndSize - d->StartSize + 1 ) >>
+ ( 4 - d->DeltaFormat ) ) + 1;
+
+ if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
+ return error;
+
+ if ( ACCESS_Frame( count * 2L ) )
+ {
+ FREE( d->DeltaValue );
+ return error;
+ }
+
+ dv = d->DeltaValue;
+
+ for ( n = 0; n < count; n++ )
+ dv[n] = GET_UShort();
+
+ FORGET_Frame();
+
+ return HB_Err_Ok;
+}
+
+
+HB_INTERNAL void
+_HB_OPEN_Free_Device( HB_Device* d )
+{
+ FREE( d->DeltaValue );
+}
+
+
+/* Since we have the delta values stored in compressed form, we must
+ uncompress it now. To simplify the interface, the function always
+ returns a meaningful value in `value'; the error is just for
+ information.
+ | |
+ format = 1: 0011223344556677|8899101112131415|...
+ | |
+ byte 1 byte 2
+
+ 00: (byte >> 14) & mask
+ 11: (byte >> 12) & mask
+ ...
+
+ mask = 0x0003
+ | |
+ format = 2: 0000111122223333|4444555566667777|...
+ | |
+ byte 1 byte 2
+
+ 0000: (byte >> 12) & mask
+ 1111: (byte >> 8) & mask
+ ...
+
+ mask = 0x000F
+ | |
+ format = 3: 0000000011111111|2222222233333333|...
+ | |
+ byte 1 byte 2
+
+ 00000000: (byte >> 8) & mask
+ 11111111: (byte >> 0) & mask
+ ....
+
+ mask = 0x00FF */
+
+HB_INTERNAL HB_Error
+_HB_OPEN_Get_Device( HB_Device* d,
+ HB_UShort size,
+ HB_Short* value )
+{
+ HB_UShort byte, bits, mask, f, s;
+
+
+ f = d->DeltaFormat;
+
+ if ( d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
+ {
+ s = size - d->StartSize;
+ byte = d->DeltaValue[s >> ( 4 - f )];
+ bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
+ mask = 0xFFFF >> ( 16 - ( 1 << f ) );
+
+ *value = (HB_Short)( bits & mask );
+
+ /* conversion to a signed value */
+
+ if ( *value >= ( ( mask + 1 ) >> 1 ) )
+ *value -= mask + 1;
+
+ return HB_Err_Ok;
+ }
+ else
+ {
+ *value = 0;
+ return HB_Err_Not_Covered;
+ }
+}
+
+
+/* END */
diff --git a/third_party/harfbuzz/src/harfbuzz-open.h b/third_party/harfbuzz/src/harfbuzz-open.h
new file mode 100644
index 0000000..bdc6358
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-open.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_OPEN_H
+#define HARFBUZZ_OPEN_H
+
+#include "harfbuzz-global.h"
+
+HB_BEGIN_HEADER
+
+/* Use this if a feature applies to all glyphs */
+#define HB_ALL_GLYPHS 0xFFFF
+
+#define HB_DEFAULT_LANGUAGE 0xFFFF
+
+#define HB_MAX_NESTING_LEVEL 100
+
+
+/* Script list related structures */
+
+struct HB_LangSys_
+{
+ HB_UShort LookupOrderOffset; /* always 0 for TT Open 1.0 */
+ HB_UShort ReqFeatureIndex; /* required FeatureIndex */
+ HB_UShort FeatureCount; /* number of Feature indices */
+ HB_UShort* FeatureIndex; /* array of Feature indices */
+};
+
+typedef struct HB_LangSys_ HB_LangSys;
+
+
+struct HB_LangSysRecord_
+{
+ HB_UInt LangSysTag; /* LangSysTag identifier */
+ HB_LangSys LangSys; /* LangSys table */
+};
+
+typedef struct HB_LangSysRecord_ HB_LangSysRecord;
+
+
+struct HB_ScriptTable_
+{
+ HB_LangSys DefaultLangSys; /* DefaultLangSys table */
+ HB_UShort LangSysCount; /* number of LangSysRecords */
+ HB_LangSysRecord* LangSysRecord; /* array of LangSysRecords */
+};
+
+typedef struct HB_ScriptTable_ HB_ScriptTable;
+
+
+struct HB_ScriptRecord_
+{
+ HB_UInt ScriptTag; /* ScriptTag identifier */
+ HB_ScriptTable Script; /* Script table */
+};
+
+typedef struct HB_ScriptRecord_ HB_ScriptRecord;
+
+
+struct HB_ScriptList_
+{
+ HB_UShort ScriptCount; /* number of ScriptRecords */
+ HB_ScriptRecord* ScriptRecord; /* array of ScriptRecords */
+};
+
+typedef struct HB_ScriptList_ HB_ScriptList;
+
+
+/* Feature list related structures */
+
+struct HB_Feature_
+{
+ HB_UShort FeatureParams; /* always 0 for TT Open 1.0 */
+ HB_UShort LookupListCount; /* number of LookupList indices */
+ HB_UShort* LookupListIndex; /* array of LookupList indices */
+};
+
+typedef struct HB_Feature_ HB_Feature;
+
+
+struct HB_FeatureRecord_
+{
+ HB_UInt FeatureTag; /* FeatureTag identifier */
+ HB_Feature Feature; /* Feature table */
+};
+
+typedef struct HB_FeatureRecord_ HB_FeatureRecord;
+
+
+struct HB_FeatureList_
+{
+ HB_UShort FeatureCount; /* number of FeatureRecords */
+ HB_FeatureRecord* FeatureRecord; /* array of FeatureRecords */
+ HB_UShort* ApplyOrder; /* order to apply features */
+ HB_UShort ApplyCount; /* number of elements in ApplyOrder */
+};
+
+typedef struct HB_FeatureList_ HB_FeatureList;
+
+
+/* Lookup list related structures */
+
+typedef struct HB_SubTable_ HB_SubTable;
+
+
+struct HB_Lookup_
+{
+ HB_UShort LookupType; /* Lookup type */
+ HB_UShort LookupFlag; /* Lookup qualifiers */
+ HB_UShort SubTableCount; /* number of SubTables */
+ HB_SubTable* SubTable; /* array of SubTables */
+};
+
+typedef struct HB_Lookup_ HB_Lookup;
+
+
+/* The `Properties' field is not defined in the OpenType specification but
+ is needed for processing lookups. If properties[n] is > 0, the
+ functions HB_GSUB_Apply_String() resp. HB_GPOS_Apply_String() will
+ process Lookup[n] for glyphs which have the specific bit not set in
+ the `properties' field of the input string object. */
+
+struct HB_LookupList_
+{
+ HB_UShort LookupCount; /* number of Lookups */
+ HB_Lookup* Lookup; /* array of Lookup records */
+ HB_UInt* Properties; /* array of flags */
+};
+
+typedef struct HB_LookupList_ HB_LookupList;
+
+
+/* Possible LookupFlag bit masks. `HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS' comes from the
+ OpenType 1.2 specification; HB_LOOKUP_FLAG_RIGHT_TO_LEFT has been (re)introduced in
+ OpenType 1.3 -- if set, the last glyph in a cursive attachment
+ sequence has to be positioned on the baseline -- regardless of the
+ writing direction. */
+
+#define HB_LOOKUP_FLAG_RIGHT_TO_LEFT 0x0001
+#define HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS 0x0002
+#define HB_LOOKUP_FLAG_IGNORE_LIGATURES 0x0004
+#define HB_LOOKUP_FLAG_IGNORE_MARKS 0x0008
+#define HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS 0xFF00
+
+
+struct HB_CoverageFormat1_
+{
+ HB_UShort GlyphCount; /* number of glyphs in GlyphArray */
+ HB_UShort* GlyphArray; /* array of glyph IDs */
+};
+
+typedef struct HB_CoverageFormat1_ HB_CoverageFormat1;
+
+
+struct HB_RangeRecord_
+{
+ HB_UShort Start; /* first glyph ID in the range */
+ HB_UShort End; /* last glyph ID in the range */
+ HB_UShort StartCoverageIndex; /* coverage index of first
+ glyph ID in the range */
+};
+
+typedef struct HB_RangeRecord_ HB_RangeRecord;
+
+
+struct HB_CoverageFormat2_
+{
+ HB_UShort RangeCount; /* number of RangeRecords */
+ HB_RangeRecord* RangeRecord; /* array of RangeRecords */
+};
+
+typedef struct HB_CoverageFormat2_ HB_CoverageFormat2;
+
+
+struct HB_Coverage_
+{
+ HB_UShort CoverageFormat; /* 1 or 2 */
+
+ union
+ {
+ HB_CoverageFormat1 cf1;
+ HB_CoverageFormat2 cf2;
+ } cf;
+};
+
+typedef struct HB_Coverage_ HB_Coverage;
+
+
+struct HB_ClassDefFormat1_
+{
+ HB_UShort StartGlyph; /* first glyph ID of the
+ ClassValueArray */
+ HB_UShort GlyphCount; /* size of the ClassValueArray */
+ HB_UShort* ClassValueArray; /* array of class values */
+};
+
+typedef struct HB_ClassDefFormat1_ HB_ClassDefFormat1;
+
+
+struct HB_ClassRangeRecord_
+{
+ HB_UShort Start; /* first glyph ID in the range */
+ HB_UShort End; /* last glyph ID in the range */
+ HB_UShort Class; /* applied to all glyphs in range */
+};
+
+typedef struct HB_ClassRangeRecord_ HB_ClassRangeRecord;
+
+
+struct HB_ClassDefFormat2_
+{
+ HB_UShort ClassRangeCount;
+ /* number of ClassRangeRecords */
+ HB_ClassRangeRecord* ClassRangeRecord;
+ /* array of ClassRangeRecords */
+};
+
+typedef struct HB_ClassDefFormat2_ HB_ClassDefFormat2;
+
+
+struct HB_ClassDefinition_
+{
+ HB_Bool loaded;
+
+ HB_UShort ClassFormat; /* 1 or 2 */
+
+ union
+ {
+ HB_ClassDefFormat1 cd1;
+ HB_ClassDefFormat2 cd2;
+ } cd;
+};
+
+typedef struct HB_ClassDefinition_ HB_ClassDefinition;
+
+
+struct HB_Device_
+{
+ HB_UShort StartSize; /* smallest size to correct */
+ HB_UShort EndSize; /* largest size to correct */
+ HB_UShort DeltaFormat; /* DeltaValue array data format:
+ 1, 2, or 3 */
+ HB_UShort* DeltaValue; /* array of compressed data */
+};
+
+typedef struct HB_Device_ HB_Device;
+
+
+enum HB_Type_
+{
+ HB_Type_GSUB,
+ HB_Type_GPOS
+};
+
+typedef enum HB_Type_ HB_Type;
+
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_OPEN_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-shape.h b/third_party/harfbuzz/src/harfbuzz-shape.h
new file mode 100644
index 0000000..4f714a3
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-shape.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Owen Taylor
+ */
+
+#include <stdint.h>
+
+/* Base Types */
+
+typedef hb_uint16 HB_CodePoint; /* UTF-16 codepoint (not character ) */
+typedef char HB_Boolean;
+typedef hb_uint32 HB_Fixed; /* 26.6 */
+typedef hb_uint32 HB_Glyph;
+typedef hb_uint32 HB_Unichar;
+
+/* Metrics reported by the font backend for use of the shaper */
+typedef struct _HB_GlyphMetrics HB_GlyphMetrics;
+struct _HB_GlyphMetrics
+{
+ HB_Fixed advance;
+
+ /* Do we need ink/logical extents for the glyph here? */
+};
+
+/*
+ * HB_Font: Abstract font interface.
+ * First pass of this might just have FT_Face *getFace();
+ */
+typedef struct _HB_Font HB_Font;
+typedef struct _HB_FontClass HB_FontClass;
+
+struct HB_FontClass {
+ HB_Glyph (*charToGlyph)(HB_Font *font, HB_Unichar chr);
+ void (*getMetrics)(HB_Font *font, HB_Glyph glyph, HB_GlyphMetrics *metrics);
+ HB_Boolean (*getSFontTable)(HB_Font *font, void **cookie, char **start, int *len);
+ HB_Boolean (*freeSFontTable)(void **cookie);
+};
+
+struct _HB_Font {
+ HB_FontClass *clazz;
+};
+
+/*
+ * Language tags, of the form en-us; represented as interned, canonicalized
+ * strings. hb_language_from_string("en_US"), hb_language_from_string("en-us")
+ * both return the same (pointer-comparable) HB_Language).
+ */
+typedef struct HB_Language_ *HB_Language;
+
+HB_Language hb_language_from_string(const char *str);
+const char *hb_language_to_string(HB_Language language);
+
+/* Special treatment for the edges of runs.
+ */
+typedef enum {
+ HB_RUN_EDGE_LINE_VISUAL_EDGE = 1 << 0,
+ HB_RUN_EDGE_LINE_LOGICAL_EDGE = 1 << 1,
+ HB_RUN_EDGE_LINE_ADD_HYPHEN = 1 << 2 /* ???? */
+} HB_RunEdge;
+
+/* Defines optional informaiton in HB_ShapeInput; this allows extension
+ * of HB_ShapeInput while keeping binary compatibility
+ */
+typedef enum {
+ HB_SHAPE_START_TYPE = 1 << 0,
+ HB_SHAPE_END_TYPE = 1 << 1
+} HB_ShapeFlags;
+
+/* Attributes types are described by "interned strings"; this is a little
+ * annoying if you want to write a switch statement, but keeps things
+ * simple.
+ */
+typedef struct _HB_AttributeType *HB_AttributeType;
+
+HB_AttributeType hb_attribute_type_from_string(const char *str);
+const char *hb_attribute_type_to_string(HB_AttributeType attribute_type);
+
+struct HB_Attribute {
+ HB_AttributeType type;
+ int start;
+ int end;
+};
+
+
+/**
+ * You could handle this like HB_Language, but an enum seems a little nicer;
+ * another approach would be to use OpenType script tags.
+ */
+typedef enum {
+ HB_SCRIPT_LATIN
+ /* ... */
+} HB_ShapeScript;
+
+/* This is just the subset of direction information needed by the shaper */
+typedef enum {
+ HB_DIRECTION_LTR,
+ HB_DIRECTION_RTL,
+ HB_DIRECTION_TTB
+} HB_Direction;
+
+typedef struct _HB_ShapeInput HB_ShapeInput;
+struct _HB_ShapeInput {
+ /* Defines what fields the caller has initialized - fields not in
+ * the enum are mandatory.
+ */
+ HB_ShapeFlags flags;
+
+ HB_CodePoint *text;
+ int length; /* total length of text to shape */
+ int shape_offset; /* start of section to shape */
+ int shape_length; /* number of code points to shape */
+
+ HB_Direction direction;
+ HB_ShapeScript script;
+ HB_Language language;
+
+ HB_AttributeType *attributes;
+ int n_attributes;
+
+ HB_RunEdge start_type;
+ HB_RunEdge end_type;
+};
+
+struct HB_GlyphItem {
+ HB_Glyph glyph;
+
+ HB_Fixed x_offset;
+ HB_Fixed y_offset;
+ HB_Fixed advance;
+
+ /* Add kashida information, etc, here */
+};
+
+typedef enum {
+ HB_RESULT_SUCCESS,
+ HB_RESULT_NO_MEMORY,
+ HB_SHAPE_RESULT_FAILED
+} HB_Result;
+
+/*
+ * Buffer for output
+ */
+typedef struct _HB_GlyphBufer HB_GlyphBuffer;
+struct _HB_GlyphBuffer {
+ int glyph_item_size;
+ int total_glyphs;
+
+ int *log_clusters; /* Uniscribe style */
+ int cluster_space;
+
+ int glyph_space;
+ void *glyph_buffer;
+};
+
+/* Making this self-allocating simplifies writing shapers and
+ * also keeps things easier for caller. item_size passed in
+ * must be at least sizeof(HB_GlyphItem) but can be bigger,
+ * to accomodate application structures that extend HB_GlyphItem.
+ * The allocated items will be zero-initialized.
+ *
+ * (Hack: Harfbuzz could choose to use even a *bigger* item size
+ * and stick internal information before the public item structure.
+ * This hack could possibly be used to unify this with HB_Buffer)
+ */
+HB_GlyphBuffer *hb_glyph_buffer_new (size_t item_size);
+void hb_glyph_buffer_clear (HB_GlyphBuffer *buf);
+HB_Result hb_glyph_buffer_extend_glyphs (HB_GlyphBuffer *buf, int n_items);
+HB_Result hb_glyph_buffer_extend_clusters (HB_GlyphBuffer *buf, int n_clusters);
+void hb_glyph_buffer_free (HB_GlyphBuffer *buf);
+
+
+/* Accessor for a particular glyph */
+#define HB_GLYPH_BUFFER_ITEM(buffer, index)
+
+/*
+ * Main shaping function
+ */
+HB_Result hb_shape(HB_ShapeInput *input, HB_GlyphBuffer *output);
diff --git a/third_party/harfbuzz/src/harfbuzz-shaper-all.cpp b/third_party/harfbuzz/src/harfbuzz-shaper-all.cpp
new file mode 100644
index 0000000..d2f902f
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-shaper-all.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.cpp"
+#include "harfbuzz-indic.cpp"
+extern "C" {
+#include "harfbuzz-tibetan.c"
+#include "harfbuzz-khmer.c"
+#include "harfbuzz-hebrew.c"
+#include "harfbuzz-arabic.c"
+#include "harfbuzz-hangul.c"
+#include "harfbuzz-myanmar.c"
+#include "harfbuzz-thai.c"
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-shaper-private.h b/third_party/harfbuzz/src/harfbuzz-shaper-private.h
new file mode 100644
index 0000000..80bccf8
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-shaper-private.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_SHAPER_PRIVATE_H
+#define HARFBUZZ_SHAPER_PRIVATE_H
+
+HB_BEGIN_HEADER
+
+enum {
+ C_DOTTED_CIRCLE = 0x25CC
+};
+
+typedef enum
+{
+ HB_Combining_BelowLeftAttached = 200,
+ HB_Combining_BelowAttached = 202,
+ HB_Combining_BelowRightAttached = 204,
+ HB_Combining_LeftAttached = 208,
+ HB_Combining_RightAttached = 210,
+ HB_Combining_AboveLeftAttached = 212,
+ HB_Combining_AboveAttached = 214,
+ HB_Combining_AboveRightAttached = 216,
+
+ HB_Combining_BelowLeft = 218,
+ HB_Combining_Below = 220,
+ HB_Combining_BelowRight = 222,
+ HB_Combining_Left = 224,
+ HB_Combining_Right = 226,
+ HB_Combining_AboveLeft = 228,
+ HB_Combining_Above = 230,
+ HB_Combining_AboveRight = 232,
+
+ HB_Combining_DoubleBelow = 233,
+ HB_Combining_DoubleAbove = 234,
+ HB_Combining_IotaSubscript = 240
+} HB_CombiningClass;
+
+typedef enum {
+ CcmpProperty = 0x1,
+ InitProperty = 0x2,
+ IsolProperty = 0x4,
+ FinaProperty = 0x8,
+ MediProperty = 0x10,
+ RligProperty = 0x20,
+ CaltProperty = 0x40,
+ LigaProperty = 0x80,
+ DligProperty = 0x100,
+ CswhProperty = 0x200,
+ MsetProperty = 0x400,
+
+ /* used by indic and myanmar shaper */
+ NuktaProperty = 0x4,
+ AkhantProperty = 0x8,
+ RephProperty = 0x10,
+ PreFormProperty = 0x20,
+ BelowFormProperty = 0x40,
+ AboveFormProperty = 0x80,
+ HalfFormProperty = 0x100,
+ PostFormProperty = 0x200,
+ VattuProperty = 0x400,
+ PreSubstProperty = 0x800,
+ BelowSubstProperty = 0x1000,
+ AboveSubstProperty = 0x2000,
+ PostSubstProperty = 0x4000,
+ HalantProperty = 0x8000,
+ CligProperty = 0x10000
+
+} HB_OpenTypeProperty;
+
+/* return true if ok. */
+typedef HB_Bool (*HB_ShapeFunction)(HB_ShaperItem *shaper_item);
+typedef void (*HB_AttributeFunction)(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+typedef struct {
+ HB_ShapeFunction shape;
+ HB_AttributeFunction charAttributes;
+} HB_ScriptEngine;
+
+extern const HB_ScriptEngine hb_scriptEngines[];
+
+extern HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_TibetanShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_ArabicShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_HangulShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_MyanmarShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_KhmerShape(HB_ShaperItem *shaper_item);
+extern HB_Bool HB_IndicShape(HB_ShaperItem *shaper_item);
+
+extern void HB_TibetanAttributes(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+extern void HB_MyanmarAttributes(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+extern void HB_KhmerAttributes(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+extern void HB_IndicAttributes(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+extern void HB_ThaiAttributes(HB_Script script, const HB_UChar16 *string, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes);
+
+typedef struct {
+ hb_uint32 tag;
+ hb_uint32 property;
+} HB_OpenTypeFeature;
+
+#define PositioningProperties 0x80000000
+
+HB_Bool HB_SelectScript(HB_ShaperItem *item, const HB_OpenTypeFeature *features);
+
+HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties);
+HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters);
+
+void HB_HeuristicPosition(HB_ShaperItem *item);
+void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item);
+
+#define HB_IsControlChar(uc) \
+ ((uc >= 0x200b && uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */) \
+ || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */) \
+ || (uc >= 0x206a && uc <= 0x206f /* ISS, ASS, IAFS, AFS, NADS, NODS */))
+
+HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item);
+
+#define HB_GetGlyphAdvances(shaper_item) \
+ shaper_item->font->klass->getGlyphAdvances(shaper_item->font, \
+ shaper_item->glyphs, shaper_item->num_glyphs, \
+ shaper_item->advances, \
+ shaper_item->face->current_flags);
+
+#define HB_DECLARE_STACKARRAY(Type, Name) \
+ Type stack##Name[512]; \
+ Type *Name = stack##Name;
+
+#define HB_INIT_STACKARRAY(Type, Name, Length) \
+ if ((Length) >= 512) \
+ Name = (Type *)malloc((Length) * sizeof(Type));
+
+#define HB_STACKARRAY(Type, Name, Length) \
+ HB_DECLARE_STACKARRAY(Type, Name) \
+ HB_INIT_STACKARRAY(Type, Name, Length)
+
+#define HB_FREE_STACKARRAY(Name) \
+ if (stack##Name != Name) \
+ free(Name);
+
+HB_END_HEADER
+
+#endif
diff --git a/third_party/harfbuzz/src/harfbuzz-shaper.cpp b/third_party/harfbuzz/src/harfbuzz-shaper.cpp
new file mode 100644
index 0000000..36b9282
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-shaper.cpp
@@ -0,0 +1,1312 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include "harfbuzz-stream-private.h"
+#include <assert.h>
+#include <stdio.h>
+
+#define HB_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define HB_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+// -----------------------------------------------------------------------------------------------------
+//
+// The line break algorithm. See http://www.unicode.org/reports/tr14/tr14-13.html
+//
+// -----------------------------------------------------------------------------------------------------
+
+/* The Unicode algorithm does in our opinion allow line breaks at some
+ places they shouldn't be allowed. The following changes were thus
+ made in comparison to the Unicode reference:
+
+ EX->AL from DB to IB
+ SY->AL from DB to IB
+ SY->PO from DB to IB
+ SY->PR from DB to IB
+ SY->OP from DB to IB
+ AL->PR from DB to IB
+ AL->PO from DB to IB
+ PR->PR from DB to IB
+ PO->PO from DB to IB
+ PR->PO from DB to IB
+ PO->PR from DB to IB
+ HY->PO from DB to IB
+ HY->PR from DB to IB
+ HY->OP from DB to IB
+ NU->EX from PB to IB
+ EX->PO from DB to IB
+*/
+
+// The following line break classes are not treated by the table:
+// AI, BK, CB, CR, LF, NL, SA, SG, SP, XX
+
+enum break_class {
+ // the first 4 values have to agree with the enum in QCharAttributes
+ ProhibitedBreak, // PB in table
+ DirectBreak, // DB in table
+ IndirectBreak, // IB in table
+ CombiningIndirectBreak, // CI in table
+ CombiningProhibitedBreak // CP in table
+};
+#define DB DirectBreak
+#define IB IndirectBreak
+#define CI CombiningIndirectBreak
+#define CP CombiningProhibitedBreak
+#define PB ProhibitedBreak
+
+static const hb_uint8 breakTable[HB_LineBreak_JT+1][HB_LineBreak_JT+1] =
+{
+/* OP CL QU GL NS EX SY IS PR PO NU AL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT */
+/* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB },
+/* CL */ { DB, PB, IB, IB, PB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* QU */ { PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
+/* GL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
+/* NS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* EX */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* SY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* IS */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* PR */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB },
+/* PO */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* NU */ { IB, PB, IB, IB, IB, IB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* AL */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* ID */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* IN */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* HY */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* BA */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* BB */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
+/* B2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB },
+/* CM */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB },
+/* WJ */ { IB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB },
+/* H2 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
+/* H3 */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB },
+/* JL */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB },
+/* JV */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB },
+/* JT */ { DB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB }
+};
+#undef DB
+#undef IB
+#undef CI
+#undef CP
+#undef PB
+
+static const hb_uint8 graphemeTable[HB_Grapheme_LVT + 1][HB_Grapheme_LVT + 1] =
+{
+// Other, CR, LF, Control,Extend,L, V, T, LV, LVT
+ { true , true , true , true , true , true , true , true , true , true }, // Other,
+ { true , true , true , true , true , true , true , true , true , true }, // CR,
+ { true , false, true , true , true , true , true , true , true , true }, // LF,
+ { true , true , true , true , true , true , true , true , true , true }, // Control,
+ { false, true , true , true , false, false, false, false, false, false }, // Extend,
+ { true , true , true , true , true , false, true , true , true , true }, // L,
+ { true , true , true , true , true , false, false, true , false, true }, // V,
+ { true , true , true , true , true , true , false, false, false, false }, // T,
+ { true , true , true , true , true , false, true , true , true , true }, // LV,
+ { true , true , true , true , true , false, true , true , true , true }, // LVT
+};
+
+static void calcLineBreaks(const HB_UChar16 *uc, hb_uint32 len, HB_CharAttributes *charAttributes)
+{
+ if (!len)
+ return;
+
+ // ##### can this fail if the first char is a surrogate?
+ HB_LineBreakClass cls;
+ HB_GraphemeClass grapheme;
+ HB_GetGraphemeAndLineBreakClass(*uc, &grapheme, &cls);
+ // handle case where input starts with an LF
+ if (cls == HB_LineBreak_LF)
+ cls = HB_LineBreak_BK;
+
+ charAttributes[0].whiteSpace = (cls == HB_LineBreak_SP || cls == HB_LineBreak_BK);
+ charAttributes[0].charStop = true;
+
+ int lcls = cls;
+ for (hb_uint32 i = 1; i < len; ++i) {
+ charAttributes[i].whiteSpace = false;
+ charAttributes[i].charStop = true;
+
+ HB_UChar32 code = uc[i];
+ HB_GraphemeClass ngrapheme;
+ HB_LineBreakClass ncls;
+ HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
+ charAttributes[i].charStop = graphemeTable[ngrapheme][grapheme];
+ // handle surrogates
+ if (ncls == HB_LineBreak_SG) {
+ if (HB_IsHighSurrogate(uc[i]) && i < len - 1 && HB_IsLowSurrogate(uc[i+1])) {
+ continue;
+ } else if (HB_IsLowSurrogate(uc[i]) && HB_IsHighSurrogate(uc[i-1])) {
+ code = HB_SurrogateToUcs4(uc[i-1], uc[i]);
+ HB_GetGraphemeAndLineBreakClass(code, &ngrapheme, &ncls);
+ charAttributes[i].charStop = false;
+ } else {
+ ncls = HB_LineBreak_AL;
+ }
+ }
+
+ // set white space and char stop flag
+ if (ncls >= HB_LineBreak_SP)
+ charAttributes[i].whiteSpace = true;
+
+ HB_LineBreakType lineBreakType = HB_NoBreak;
+ if (cls >= HB_LineBreak_LF) {
+ lineBreakType = HB_ForcedBreak;
+ } else if(cls == HB_LineBreak_CR) {
+ lineBreakType = (ncls == HB_LineBreak_LF) ? HB_NoBreak : HB_ForcedBreak;
+ }
+
+ if (ncls == HB_LineBreak_SP)
+ goto next_no_cls_update;
+ if (ncls >= HB_LineBreak_CR)
+ goto next;
+
+ // two complex chars (thai or lao), thai_attributes might override, but here we do a best guess
+ if (cls == HB_LineBreak_SA && ncls == HB_LineBreak_SA) {
+ lineBreakType = HB_Break;
+ goto next;
+ }
+
+ {
+ int tcls = ncls;
+ if (tcls >= HB_LineBreak_SA)
+ tcls = HB_LineBreak_ID;
+ if (cls >= HB_LineBreak_SA)
+ cls = HB_LineBreak_ID;
+
+ int brk = breakTable[cls][tcls];
+ switch (brk) {
+ case DirectBreak:
+ lineBreakType = HB_Break;
+ if (uc[i-1] == 0xad) // soft hyphen
+ lineBreakType = HB_SoftHyphen;
+ break;
+ case IndirectBreak:
+ lineBreakType = (lcls == HB_LineBreak_SP) ? HB_Break : HB_NoBreak;
+ break;
+ case CombiningIndirectBreak:
+ lineBreakType = HB_NoBreak;
+ if (lcls == HB_LineBreak_SP){
+ if (i > 1)
+ charAttributes[i-2].lineBreakType = HB_Break;
+ } else {
+ goto next_no_cls_update;
+ }
+ break;
+ case CombiningProhibitedBreak:
+ lineBreakType = HB_NoBreak;
+ if (lcls != HB_LineBreak_SP)
+ goto next_no_cls_update;
+ case ProhibitedBreak:
+ default:
+ break;
+ }
+ }
+ next:
+ cls = ncls;
+ next_no_cls_update:
+ lcls = ncls;
+ grapheme = ngrapheme;
+ charAttributes[i-1].lineBreakType = lineBreakType;
+ }
+ charAttributes[len-1].lineBreakType = HB_ForcedBreak;
+}
+
+// --------------------------------------------------------------------------------------------------------------------------------------------
+//
+// Basic processing
+//
+// --------------------------------------------------------------------------------------------------------------------------------------------
+
+static inline void positionCluster(HB_ShaperItem *item, int gfrom, int glast)
+{
+ int nmarks = glast - gfrom;
+ assert(nmarks > 0);
+
+ HB_Glyph *glyphs = item->glyphs;
+ HB_GlyphAttributes *attributes = item->attributes;
+
+ HB_GlyphMetrics baseMetrics;
+ item->font->klass->getGlyphMetrics(item->font, glyphs[gfrom], &baseMetrics);
+
+ if (item->item.script == HB_Script_Hebrew
+ && (-baseMetrics.y) > baseMetrics.height)
+ // we need to attach below the baseline, because of the hebrew iud.
+ baseMetrics.height = -baseMetrics.y;
+
+// qDebug("---> positionCluster: cluster from %d to %d", gfrom, glast);
+// qDebug("baseInfo: %f/%f (%f/%f) off=%f/%f", baseInfo.x, baseInfo.y, baseInfo.width, baseInfo.height, baseInfo.xoff, baseInfo.yoff);
+
+ HB_Fixed size = item->font->klass->getFontMetric(item->font, HB_FontAscent) / 10;
+ HB_Fixed offsetBase = HB_FIXED_CONSTANT(1) + (size - HB_FIXED_CONSTANT(4)) / 4;
+ if (size > HB_FIXED_CONSTANT(4))
+ offsetBase += HB_FIXED_CONSTANT(4);
+ else
+ offsetBase += size;
+ //qreal offsetBase = (size - 4) / 4 + qMin<qreal>(size, 4) + 1;
+// qDebug("offset = %f", offsetBase);
+
+ bool rightToLeft = item->item.bidiLevel % 2;
+
+ int i;
+ unsigned char lastCmb = 0;
+ HB_GlyphMetrics attachmentRect;
+ memset(&attachmentRect, 0, sizeof(attachmentRect));
+
+ for(i = 1; i <= nmarks; i++) {
+ HB_Glyph mark = glyphs[gfrom+i];
+ HB_GlyphMetrics markMetrics;
+ item->font->klass->getGlyphMetrics(item->font, mark, &markMetrics);
+ HB_FixedPoint p;
+ p.x = p.y = 0;
+// qDebug("markInfo: %f/%f (%f/%f) off=%f/%f", markInfo.x, markInfo.y, markInfo.width, markInfo.height, markInfo.xoff, markInfo.yoff);
+
+ HB_Fixed offset = offsetBase;
+ unsigned char cmb = attributes[gfrom+i].combiningClass;
+
+ // ### maybe the whole position determination should move down to heuristicSetGlyphAttributes. Would save some
+ // bits in the glyphAttributes structure.
+ if (cmb < 200) {
+ // fixed position classes. We approximate by mapping to one of the others.
+ // currently I added only the ones for arabic, hebrew, lao and thai.
+
+ // for Lao and Thai marks with class 0, see below (heuristicSetGlyphAttributes)
+
+ // add a bit more offset to arabic, a bit hacky
+ if (cmb >= 27 && cmb <= 36 && offset < 3)
+ offset +=1;
+ // below
+ if ((cmb >= 10 && cmb <= 18) ||
+ cmb == 20 || cmb == 22 ||
+ cmb == 29 || cmb == 32)
+ cmb = HB_Combining_Below;
+ // above
+ else if (cmb == 23 || cmb == 27 || cmb == 28 ||
+ cmb == 30 || cmb == 31 || (cmb >= 33 && cmb <= 36))
+ cmb = HB_Combining_Above;
+ //below-right
+ else if (cmb == 9 || cmb == 103 || cmb == 118)
+ cmb = HB_Combining_BelowRight;
+ // above-right
+ else if (cmb == 24 || cmb == 107 || cmb == 122)
+ cmb = HB_Combining_AboveRight;
+ else if (cmb == 25)
+ cmb = HB_Combining_AboveLeft;
+ // fixed:
+ // 19 21
+
+ }
+
+ // combining marks of different class don't interact. Reset the rectangle.
+ if (cmb != lastCmb) {
+ //qDebug("resetting rect");
+ attachmentRect = baseMetrics;
+ }
+
+ switch(cmb) {
+ case HB_Combining_DoubleBelow:
+ // ### wrong in rtl context!
+ case HB_Combining_BelowLeft:
+ p.y += offset;
+ case HB_Combining_BelowLeftAttached:
+ p.x += attachmentRect.x - markMetrics.x;
+ p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
+ break;
+ case HB_Combining_Below:
+ p.y += offset;
+ case HB_Combining_BelowAttached:
+ p.x += attachmentRect.x - markMetrics.x;
+ p.y += (attachmentRect.y + attachmentRect.height) - markMetrics.y;
+
+ p.x += (attachmentRect.width - markMetrics.width) / 2;
+ break;
+ case HB_Combining_BelowRight:
+ p.y += offset;
+ case HB_Combining_BelowRightAttached:
+ p.x += attachmentRect.x + attachmentRect.width - markMetrics.width - markMetrics.x;
+ p.y += attachmentRect.y + attachmentRect.height - markMetrics.y;
+ break;
+ case HB_Combining_Left:
+ p.x -= offset;
+ case HB_Combining_LeftAttached:
+ break;
+ case HB_Combining_Right:
+ p.x += offset;
+ case HB_Combining_RightAttached:
+ break;
+ case HB_Combining_DoubleAbove:
+ // ### wrong in RTL context!
+ case HB_Combining_AboveLeft:
+ p.y -= offset;
+ case HB_Combining_AboveLeftAttached:
+ p.x += attachmentRect.x - markMetrics.x;
+ p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
+ break;
+ case HB_Combining_Above:
+ p.y -= offset;
+ case HB_Combining_AboveAttached:
+ p.x += attachmentRect.x - markMetrics.x;
+ p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
+
+ p.x += (attachmentRect.width - markMetrics.width) / 2;
+ break;
+ case HB_Combining_AboveRight:
+ p.y -= offset;
+ case HB_Combining_AboveRightAttached:
+ p.x += attachmentRect.x + attachmentRect.width - markMetrics.x - markMetrics.width;
+ p.y += attachmentRect.y - markMetrics.y - markMetrics.height;
+ break;
+
+ case HB_Combining_IotaSubscript:
+ default:
+ break;
+ }
+// qDebug("char=%x combiningClass = %d offset=%f/%f", mark, cmb, p.x(), p.y());
+ markMetrics.x += p.x;
+ markMetrics.y += p.y;
+
+ HB_GlyphMetrics unitedAttachmentRect = attachmentRect;
+ unitedAttachmentRect.x = HB_MIN(attachmentRect.x, markMetrics.x);
+ unitedAttachmentRect.y = HB_MIN(attachmentRect.y, markMetrics.y);
+ unitedAttachmentRect.width = HB_MAX(attachmentRect.x + attachmentRect.width, markMetrics.x + markMetrics.width) - unitedAttachmentRect.x;
+ unitedAttachmentRect.height = HB_MAX(attachmentRect.y + attachmentRect.height, markMetrics.y + markMetrics.height) - unitedAttachmentRect.y;
+ attachmentRect = unitedAttachmentRect;
+
+ lastCmb = cmb;
+ if (rightToLeft) {
+ item->offsets[gfrom+i].x = p.x;
+ item->offsets[gfrom+i].y = p.y;
+ } else {
+ item->offsets[gfrom+i].x = p.x - baseMetrics.xOffset;
+ item->offsets[gfrom+i].y = p.y - baseMetrics.yOffset;
+ }
+ item->advances[gfrom+i] = 0;
+ }
+}
+
+void HB_HeuristicPosition(HB_ShaperItem *item)
+{
+ HB_GetGlyphAdvances(item);
+ HB_GlyphAttributes *attributes = item->attributes;
+
+ int cEnd = -1;
+ int i = item->num_glyphs;
+ while (i--) {
+ if (cEnd == -1 && attributes[i].mark) {
+ cEnd = i;
+ } else if (cEnd != -1 && !attributes[i].mark) {
+ positionCluster(item, i, cEnd);
+ cEnd = -1;
+ }
+ }
+}
+
+// set the glyph attributes heuristically. Assumes a 1 to 1 relationship between chars and glyphs
+// and no reordering.
+// also computes logClusters heuristically
+void HB_HeuristicSetGlyphAttributes(HB_ShaperItem *item)
+{
+ const HB_UChar16 *uc = item->string + item->item.pos;
+ hb_uint32 length = item->item.length;
+
+ // ### zeroWidth and justification are missing here!!!!!
+
+ assert(item->num_glyphs <= length);
+
+// qDebug("QScriptEngine::heuristicSetGlyphAttributes, num_glyphs=%d", item->num_glyphs);
+ HB_GlyphAttributes *attributes = item->attributes;
+ unsigned short *logClusters = item->log_clusters;
+
+ hb_uint32 glyph_pos = 0;
+ hb_uint32 i;
+ for (i = 0; i < length; i++) {
+ if (HB_IsHighSurrogate(uc[i]) && i < length - 1
+ && HB_IsLowSurrogate(uc[i + 1])) {
+ logClusters[i] = glyph_pos;
+ logClusters[++i] = glyph_pos;
+ } else {
+ logClusters[i] = glyph_pos;
+ }
+ ++glyph_pos;
+ }
+ assert(glyph_pos == item->num_glyphs);
+
+ // first char in a run is never (treated as) a mark
+ int cStart = 0;
+ const bool symbolFont = item->face->isSymbolFont;
+ attributes[0].mark = false;
+ attributes[0].clusterStart = true;
+ attributes[0].dontPrint = (!symbolFont && uc[0] == 0x00ad) || HB_IsControlChar(uc[0]);
+
+ int pos = 0;
+ HB_CharCategory lastCat;
+ int dummy;
+ HB_GetUnicodeCharProperties(uc[0], &lastCat, &dummy);
+ for (i = 1; i < length; ++i) {
+ if (logClusters[i] == pos)
+ // same glyph
+ continue;
+ ++pos;
+ while (pos < logClusters[i]) {
+ attributes[pos] = attributes[pos-1];
+ ++pos;
+ }
+ // hide soft-hyphens by default
+ if ((!symbolFont && uc[i] == 0x00ad) || HB_IsControlChar(uc[i]))
+ attributes[pos].dontPrint = true;
+ HB_CharCategory cat;
+ int cmb;
+ HB_GetUnicodeCharProperties(uc[i], &cat, &cmb);
+ if (cat != HB_Mark_NonSpacing) {
+ attributes[pos].mark = false;
+ attributes[pos].clusterStart = true;
+ attributes[pos].combiningClass = 0;
+ cStart = logClusters[i];
+ } else {
+ if (cmb == 0) {
+ // Fix 0 combining classes
+ if ((uc[pos] & 0xff00) == 0x0e00) {
+ // thai or lao
+ if (uc[pos] == 0xe31 ||
+ uc[pos] == 0xe34 ||
+ uc[pos] == 0xe35 ||
+ uc[pos] == 0xe36 ||
+ uc[pos] == 0xe37 ||
+ uc[pos] == 0xe47 ||
+ uc[pos] == 0xe4c ||
+ uc[pos] == 0xe4d ||
+ uc[pos] == 0xe4e) {
+ cmb = HB_Combining_AboveRight;
+ } else if (uc[pos] == 0xeb1 ||
+ uc[pos] == 0xeb4 ||
+ uc[pos] == 0xeb5 ||
+ uc[pos] == 0xeb6 ||
+ uc[pos] == 0xeb7 ||
+ uc[pos] == 0xebb ||
+ uc[pos] == 0xecc ||
+ uc[pos] == 0xecd) {
+ cmb = HB_Combining_Above;
+ } else if (uc[pos] == 0xebc) {
+ cmb = HB_Combining_Below;
+ }
+ }
+ }
+
+ attributes[pos].mark = true;
+ attributes[pos].clusterStart = false;
+ attributes[pos].combiningClass = cmb;
+ logClusters[i] = cStart;
+ }
+ // one gets an inter character justification point if the current char is not a non spacing mark.
+ // as then the current char belongs to the last one and one gets a space justification point
+ // after the space char.
+ if (lastCat == HB_Separator_Space)
+ attributes[pos-1].justification = HB_Space;
+ else if (cat != HB_Mark_NonSpacing)
+ attributes[pos-1].justification = HB_Character;
+ else
+ attributes[pos-1].justification = HB_NoJustification;
+
+ lastCat = cat;
+ }
+ pos = logClusters[length-1];
+ if (lastCat == HB_Separator_Space)
+ attributes[pos].justification = HB_Space;
+ else
+ attributes[pos].justification = HB_Character;
+}
+
+#ifndef NO_OPENTYPE
+static const HB_OpenTypeFeature basic_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('l', 'i', 'g', 'a'), CcmpProperty },
+ { HB_MAKE_TAG('c', 'l', 'i', 'g'), CcmpProperty },
+ {0, 0}
+};
+#endif
+
+HB_Bool HB_ConvertStringToGlyphIndices(HB_ShaperItem *shaper_item)
+{
+ if (shaper_item->glyphIndicesPresent) {
+ shaper_item->num_glyphs = shaper_item->initialGlyphCount;
+ shaper_item->glyphIndicesPresent = false;
+ return true;
+ }
+ return shaper_item->font->klass
+ ->convertStringToGlyphIndices(shaper_item->font,
+ shaper_item->string + shaper_item->item.pos, shaper_item->item.length,
+ shaper_item->glyphs, &shaper_item->num_glyphs,
+ shaper_item->item.bidiLevel % 2);
+}
+
+HB_Bool HB_BasicShape(HB_ShaperItem *shaper_item)
+{
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = shaper_item->num_glyphs;
+#endif
+
+ if (!HB_ConvertStringToGlyphIndices(shaper_item))
+ return false;
+
+ HB_HeuristicSetGlyphAttributes(shaper_item);
+
+#ifndef NO_OPENTYPE
+ if (HB_SelectScript(shaper_item, basic_features)) {
+ HB_OpenTypeShape(shaper_item, /*properties*/0);
+ return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/true);
+ }
+#endif
+
+ HB_HeuristicPosition(shaper_item);
+ return true;
+}
+
+const HB_ScriptEngine HB_ScriptEngines[] = {
+ // Common
+ { HB_BasicShape, 0},
+ // Greek
+ { HB_BasicShape, 0},
+ // Cyrillic
+ { HB_BasicShape, 0},
+ // Armenian
+ { HB_BasicShape, 0},
+ // Hebrew
+ { HB_HebrewShape, 0 },
+ // Arabic
+ { HB_ArabicShape, 0},
+ // Syriac
+ { HB_ArabicShape, 0},
+ // Thaana
+ { HB_BasicShape, 0 },
+ // Devanagari
+ { HB_IndicShape, HB_IndicAttributes },
+ // Bengali
+ { HB_IndicShape, HB_IndicAttributes },
+ // Gurmukhi
+ { HB_IndicShape, HB_IndicAttributes },
+ // Gujarati
+ { HB_IndicShape, HB_IndicAttributes },
+ // Oriya
+ { HB_IndicShape, HB_IndicAttributes },
+ // Tamil
+ { HB_IndicShape, HB_IndicAttributes },
+ // Telugu
+ { HB_IndicShape, HB_IndicAttributes },
+ // Kannada
+ { HB_IndicShape, HB_IndicAttributes },
+ // Malayalam
+ { HB_IndicShape, HB_IndicAttributes },
+ // Sinhala
+ { HB_IndicShape, HB_IndicAttributes },
+ // Thai
+ { HB_BasicShape, HB_ThaiAttributes },
+ // Lao
+ { HB_BasicShape, 0 },
+ // Tibetan
+ { HB_TibetanShape, HB_TibetanAttributes },
+ // Myanmar
+ { HB_MyanmarShape, HB_MyanmarAttributes },
+ // Georgian
+ { HB_BasicShape, 0 },
+ // Hangul
+ { HB_HangulShape, 0 },
+ // Ogham
+ { HB_BasicShape, 0 },
+ // Runic
+ { HB_BasicShape, 0 },
+ // Khmer
+ { HB_KhmerShape, HB_KhmerAttributes }
+};
+
+void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem *items, hb_uint32 numItems,
+ HB_CharAttributes *attributes)
+{
+ calcLineBreaks(string, stringLength, attributes);
+
+ for (hb_uint32 i = 0; i < numItems; ++i) {
+ HB_Script script = items[i].script;
+ if (script == HB_Script_Inherited)
+ script = HB_Script_Common;
+ HB_AttributeFunction attributeFunction = HB_ScriptEngines[script].charAttributes;
+ if (!attributeFunction)
+ continue;
+ attributeFunction(script, string, items[i].pos, items[i].length, attributes);
+ }
+}
+
+
+enum BreakRule { NoBreak = 0, Break = 1, Middle = 2 };
+
+static const hb_uint8 wordbreakTable[HB_Word_ExtendNumLet + 1][HB_Word_ExtendNumLet + 1] = {
+// Other Format Katakana ALetter MidLetter MidNum Numeric ExtendNumLet
+ { Break, Break, Break, Break, Break, Break, Break, Break }, // Other
+ { Break, Break, Break, Break, Break, Break, Break, Break }, // Format
+ { Break, Break, NoBreak, Break, Break, Break, Break, NoBreak }, // Katakana
+ { Break, Break, Break, NoBreak, Middle, Break, NoBreak, NoBreak }, // ALetter
+ { Break, Break, Break, Break, Break, Break, Break, Break }, // MidLetter
+ { Break, Break, Break, Break, Break, Break, Break, Break }, // MidNum
+ { Break, Break, Break, NoBreak, Break, Middle, NoBreak, NoBreak }, // Numeric
+ { Break, Break, NoBreak, NoBreak, Break, Break, NoBreak, NoBreak }, // ExtendNumLet
+};
+
+void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
+ HB_CharAttributes *attributes)
+{
+ if (stringLength == 0)
+ return;
+ unsigned int brk = HB_GetWordClass(string[0]);
+ attributes[0].wordBoundary = true;
+ for (hb_uint32 i = 1; i < stringLength; ++i) {
+ if (!attributes[i].charStop) {
+ attributes[i].wordBoundary = false;
+ continue;
+ }
+ hb_uint32 nbrk = HB_GetWordClass(string[i]);
+ if (nbrk == HB_Word_Format) {
+ attributes[i].wordBoundary = (HB_GetSentenceClass(string[i-1]) == HB_Sentence_Sep);
+ continue;
+ }
+ BreakRule rule = (BreakRule)wordbreakTable[brk][nbrk];
+ if (rule == Middle) {
+ rule = Break;
+ hb_uint32 lookahead = i + 1;
+ while (lookahead < stringLength) {
+ hb_uint32 testbrk = HB_GetWordClass(string[lookahead]);
+ if (testbrk == HB_Word_Format && HB_GetSentenceClass(string[lookahead]) != HB_Sentence_Sep) {
+ ++lookahead;
+ continue;
+ }
+ if (testbrk == brk) {
+ rule = NoBreak;
+ while (i < lookahead)
+ attributes[i++].wordBoundary = false;
+ nbrk = testbrk;
+ }
+ break;
+ }
+ }
+ attributes[i].wordBoundary = (rule == Break);
+ brk = nbrk;
+ }
+}
+
+
+enum SentenceBreakStates {
+ SB_Initial,
+ SB_Upper,
+ SB_UpATerm,
+ SB_ATerm,
+ SB_ATermC,
+ SB_ACS,
+ SB_STerm,
+ SB_STermC,
+ SB_SCS,
+ SB_BAfter,
+ SB_Break,
+ SB_Look
+};
+
+static const hb_uint8 sentenceBreakTable[HB_Sentence_Close + 1][HB_Sentence_Close + 1] = {
+// Other Sep Format Sp Lower Upper OLetter Numeric ATerm STerm Close
+ { SB_Initial, SB_BAfter , SB_Initial, SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_ATerm , SB_STerm , SB_Initial }, // SB_Initial,
+ { SB_Initial, SB_BAfter , SB_Upper , SB_Initial, SB_Initial, SB_Upper , SB_Initial, SB_Initial, SB_UpATerm, SB_STerm , SB_Initial }, // SB_Upper
+
+ { SB_Look , SB_BAfter , SB_UpATerm, SB_ACS , SB_Initial, SB_Upper , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_UpATerm
+ { SB_Look , SB_BAfter , SB_ATerm , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Initial, SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATerm
+ { SB_Look , SB_BAfter , SB_ATermC , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_ATermC }, // SB_ATermC,
+ { SB_Look , SB_BAfter , SB_ACS , SB_ACS , SB_Initial, SB_Break , SB_Break , SB_Look , SB_ATerm , SB_STerm , SB_Look }, // SB_ACS,
+
+ { SB_Break , SB_BAfter , SB_STerm , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STerm,
+ { SB_Break , SB_BAfter , SB_STermC , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_STermC }, // SB_STermC,
+ { SB_Break , SB_BAfter , SB_SCS , SB_SCS , SB_Break , SB_Break , SB_Break , SB_Break , SB_ATerm , SB_STerm , SB_Break }, // SB_SCS,
+ { SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break , SB_Break }, // SB_BAfter,
+};
+
+void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem * /*items*/, hb_uint32 /*numItems*/,
+ HB_CharAttributes *attributes)
+{
+ if (stringLength == 0)
+ return;
+ hb_uint32 brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[0])];
+ attributes[0].sentenceBoundary = true;
+ for (hb_uint32 i = 1; i < stringLength; ++i) {
+ if (!attributes[i].charStop) {
+ attributes[i].sentenceBoundary = false;
+ continue;
+ }
+ brk = sentenceBreakTable[brk][HB_GetSentenceClass(string[i])];
+ if (brk == SB_Look) {
+ brk = SB_Break;
+ hb_uint32 lookahead = i + 1;
+ while (lookahead < stringLength) {
+ hb_uint32 sbrk = HB_GetSentenceClass(string[lookahead]);
+ if (sbrk != HB_Sentence_Other && sbrk != HB_Sentence_Numeric && sbrk != HB_Sentence_Close) {
+ break;
+ } else if (sbrk == HB_Sentence_Lower) {
+ brk = SB_Initial;
+ break;
+ }
+ ++lookahead;
+ }
+ if (brk == SB_Initial) {
+ while (i < lookahead)
+ attributes[i++].sentenceBoundary = false;
+ }
+ }
+ if (brk == SB_Break) {
+ attributes[i].sentenceBoundary = true;
+ brk = sentenceBreakTable[SB_Initial][HB_GetSentenceClass(string[i])];
+ } else {
+ attributes[i].sentenceBoundary = false;
+ }
+ }
+}
+
+
+static inline char *tag_to_string(HB_UInt tag)
+{
+ static char string[5];
+ string[0] = (tag >> 24)&0xff;
+ string[1] = (tag >> 16)&0xff;
+ string[2] = (tag >> 8)&0xff;
+ string[3] = tag&0xff;
+ string[4] = 0;
+ return string;
+}
+
+#ifdef OT_DEBUG
+static void dump_string(HB_Buffer buffer)
+{
+ for (uint i = 0; i < buffer->in_length; ++i) {
+ qDebug(" %x: cluster=%d", buffer->in_string[i].gindex, buffer->in_string[i].cluster);
+ }
+}
+#define DEBUG printf
+#else
+#define DEBUG if (1) ; else printf
+#endif
+
+#define DefaultLangSys 0xffff
+#define DefaultScript HB_MAKE_TAG('D', 'F', 'L', 'T')
+
+enum {
+ RequiresGsub = 1,
+ RequiresGpos = 2
+};
+
+struct OTScripts {
+ unsigned int tag;
+ int flags;
+};
+static const OTScripts ot_scripts [] = {
+ // Common
+ { HB_MAKE_TAG('l', 'a', 't', 'n'), 0 },
+ // Greek
+ { HB_MAKE_TAG('g', 'r', 'e', 'k'), 0 },
+ // Cyrillic
+ { HB_MAKE_TAG('c', 'y', 'r', 'l'), 0 },
+ // Armenian
+ { HB_MAKE_TAG('a', 'r', 'm', 'n'), 0 },
+ // Hebrew
+ { HB_MAKE_TAG('h', 'e', 'b', 'r'), 1 },
+ // Arabic
+ { HB_MAKE_TAG('a', 'r', 'a', 'b'), 1 },
+ // Syriac
+ { HB_MAKE_TAG('s', 'y', 'r', 'c'), 1 },
+ // Thaana
+ { HB_MAKE_TAG('t', 'h', 'a', 'a'), 1 },
+ // Devanagari
+ { HB_MAKE_TAG('d', 'e', 'v', 'a'), 1 },
+ // Bengali
+ { HB_MAKE_TAG('b', 'e', 'n', 'g'), 1 },
+ // Gurmukhi
+ { HB_MAKE_TAG('g', 'u', 'r', 'u'), 1 },
+ // Gujarati
+ { HB_MAKE_TAG('g', 'u', 'j', 'r'), 1 },
+ // Oriya
+ { HB_MAKE_TAG('o', 'r', 'y', 'a'), 1 },
+ // Tamil
+ { HB_MAKE_TAG('t', 'a', 'm', 'l'), 1 },
+ // Telugu
+ { HB_MAKE_TAG('t', 'e', 'l', 'u'), 1 },
+ // Kannada
+ { HB_MAKE_TAG('k', 'n', 'd', 'a'), 1 },
+ // Malayalam
+ { HB_MAKE_TAG('m', 'l', 'y', 'm'), 1 },
+ // Sinhala
+ { HB_MAKE_TAG('s', 'i', 'n', 'h'), 1 },
+ // Thai
+ { HB_MAKE_TAG('t', 'h', 'a', 'i'), 1 },
+ // Lao
+ { HB_MAKE_TAG('l', 'a', 'o', ' '), 1 },
+ // Tibetan
+ { HB_MAKE_TAG('t', 'i', 'b', 't'), 1 },
+ // Myanmar
+ { HB_MAKE_TAG('m', 'y', 'm', 'r'), 1 },
+ // Georgian
+ { HB_MAKE_TAG('g', 'e', 'o', 'r'), 0 },
+ // Hangul
+ { HB_MAKE_TAG('h', 'a', 'n', 'g'), 1 },
+ // Ogham
+ { HB_MAKE_TAG('o', 'g', 'a', 'm'), 0 },
+ // Runic
+ { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 },
+ // Khmer
+ { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 }
+};
+enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) };
+
+static HB_Bool checkScript(HB_Face face, int script)
+{
+ assert(script < HB_ScriptCount);
+
+ if (!face->gsub && !face->gpos)
+ return false;
+
+ unsigned int tag = ot_scripts[script].tag;
+ int requirements = ot_scripts[script].flags;
+
+ if (requirements & RequiresGsub) {
+ if (!face->gsub)
+ return false;
+
+ HB_UShort script_index;
+ HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
+ if (error) {
+ DEBUG("could not select script %d in GSub table: %d", (int)script, error);
+ error = HB_GSUB_Select_Script(face->gsub, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
+ if (error)
+ return false;
+ }
+ }
+
+ if (requirements & RequiresGpos) {
+ if (!face->gpos)
+ return false;
+
+ HB_UShort script_index;
+ HB_Error error = HB_GPOS_Select_Script(face->gpos, script, &script_index);
+ if (error) {
+ DEBUG("could not select script in gpos table: %d", error);
+ error = HB_GPOS_Select_Script(face->gpos, HB_MAKE_TAG('D', 'F', 'L', 'T'), &script_index);
+ if (error)
+ return false;
+ }
+
+ }
+ return true;
+}
+
+static HB_Stream getTableStream(void *font, HB_GetFontTableFunc tableFunc, HB_Tag tag)
+{
+ HB_Error error;
+ HB_UInt length = 0;
+ HB_Stream stream = 0;
+
+ if (!font)
+ return 0;
+
+ error = tableFunc(font, tag, 0, &length);
+ if (error)
+ return 0;
+ stream = (HB_Stream)malloc(sizeof(HB_StreamRec));
+ stream->base = (HB_Byte*)malloc(length);
+ error = tableFunc(font, tag, stream->base, &length);
+ if (error) {
+ _hb_close_stream(stream);
+ return 0;
+ }
+ stream->size = length;
+ stream->pos = 0;
+ stream->cursor = NULL;
+ return stream;
+}
+
+HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc)
+{
+ HB_Face face = (HB_Face )malloc(sizeof(HB_FaceRec));
+
+ face->isSymbolFont = false;
+ face->gdef = 0;
+ face->gpos = 0;
+ face->gsub = 0;
+ face->current_script = HB_ScriptCount;
+ face->current_flags = HB_ShaperFlag_Default;
+ face->has_opentype_kerning = false;
+ face->tmpAttributes = 0;
+ face->tmpLogClusters = 0;
+ face->glyphs_substituted = false;
+
+ HB_Error error;
+ HB_Stream stream;
+ HB_Stream gdefStream;
+
+ gdefStream = getTableStream(font, tableFunc, TTAG_GDEF);
+ if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) {
+ //DEBUG("error loading gdef table: %d", error);
+ face->gdef = 0;
+ }
+
+ //DEBUG() << "trying to load gsub table";
+ stream = getTableStream(font, tableFunc, TTAG_GSUB);
+ if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) {
+ face->gsub = 0;
+ if (error != HB_Err_Not_Covered) {
+ //DEBUG("error loading gsub table: %d", error);
+ } else {
+ //DEBUG("face doesn't have a gsub table");
+ }
+ }
+ _hb_close_stream(stream);
+
+ stream = getTableStream(font, tableFunc, TTAG_GPOS);
+ if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) {
+ face->gpos = 0;
+ DEBUG("error loading gpos table: %d", error);
+ }
+ _hb_close_stream(stream);
+
+ _hb_close_stream(gdefStream);
+
+ for (unsigned int i = 0; i < HB_ScriptCount; ++i)
+ face->supported_scripts[i] = checkScript(face, i);
+
+ hb_buffer_new(&face->buffer);
+
+ return face;
+}
+
+void HB_FreeFace(HB_Face face)
+{
+ if (!face)
+ return;
+ if (face->gpos)
+ HB_Done_GPOS_Table(face->gpos);
+ if (face->gsub)
+ HB_Done_GSUB_Table(face->gsub);
+ if (face->gdef)
+ HB_Done_GDEF_Table(face->gdef);
+ if (face->buffer)
+ hb_buffer_free(face->buffer);
+ if (face->tmpAttributes)
+ free(face->tmpAttributes);
+ if (face->tmpLogClusters)
+ free(face->tmpLogClusters);
+ free(face);
+}
+
+HB_Bool HB_SelectScript(HB_ShaperItem *shaper_item, const HB_OpenTypeFeature *features)
+{
+ HB_Script script = shaper_item->item.script;
+
+ if (!shaper_item->face->supported_scripts[script])
+ return false;
+
+ HB_Face face = shaper_item->face;
+ if (face->current_script == script && face->current_flags == shaper_item->shaperFlags)
+ return true;
+
+ face->current_script = script;
+ face->current_flags = shaper_item->shaperFlags;
+
+ assert(script < HB_ScriptCount);
+ // find script in our list of supported scripts.
+ unsigned int tag = ot_scripts[script].tag;
+
+ if (face->gsub && features) {
+#ifdef OT_DEBUG
+ {
+ HB_FeatureList featurelist = face->gsub->FeatureList;
+ int numfeatures = featurelist.FeatureCount;
+ DEBUG("gsub table has %d features", numfeatures);
+ for (int i = 0; i < numfeatures; i++) {
+ HB_FeatureRecord *r = featurelist.FeatureRecord + i;
+ DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
+ }
+ }
+#endif
+ HB_GSUB_Clear_Features(face->gsub);
+ HB_UShort script_index;
+ HB_Error error = HB_GSUB_Select_Script(face->gsub, tag, &script_index);
+ if (!error) {
+ DEBUG("script %s has script index %d", tag_to_string(script), script_index);
+ while (features->tag) {
+ HB_UShort feature_index;
+ error = HB_GSUB_Select_Feature(face->gsub, features->tag, script_index, 0xffff, &feature_index);
+ if (!error) {
+ DEBUG(" adding feature %s", tag_to_string(features->tag));
+ HB_GSUB_Add_Feature(face->gsub, feature_index, features->property);
+ }
+ ++features;
+ }
+ }
+ }
+
+ // reset
+ face->has_opentype_kerning = false;
+
+ if (face->gpos) {
+ HB_GPOS_Clear_Features(face->gpos);
+ HB_UShort script_index;
+ HB_Error error = HB_GPOS_Select_Script(face->gpos, tag, &script_index);
+ if (!error) {
+#ifdef OT_DEBUG
+ {
+ HB_FeatureList featurelist = face->gpos->FeatureList;
+ int numfeatures = featurelist.FeatureCount;
+ DEBUG("gpos table has %d features", numfeatures);
+ for(int i = 0; i < numfeatures; i++) {
+ HB_FeatureRecord *r = featurelist.FeatureRecord + i;
+ HB_UShort feature_index;
+ HB_GPOS_Select_Feature(face->gpos, r->FeatureTag, script_index, 0xffff, &feature_index);
+ DEBUG(" feature '%s'", tag_to_string(r->FeatureTag));
+ }
+ }
+#endif
+ HB_UInt *feature_tag_list_buffer;
+ error = HB_GPOS_Query_Features(face->gpos, script_index, 0xffff, &feature_tag_list_buffer);
+ if (!error) {
+ HB_UInt *feature_tag_list = feature_tag_list_buffer;
+ while (*feature_tag_list) {
+ HB_UShort feature_index;
+ if (*feature_tag_list == HB_MAKE_TAG('k', 'e', 'r', 'n')) {
+ if (face->current_flags & HB_ShaperFlag_NoKerning) {
+ ++feature_tag_list;
+ continue;
+ }
+ face->has_opentype_kerning = true;
+ }
+ error = HB_GPOS_Select_Feature(face->gpos, *feature_tag_list, script_index, 0xffff, &feature_index);
+ if (!error)
+ HB_GPOS_Add_Feature(face->gpos, feature_index, PositioningProperties);
+ ++feature_tag_list;
+ }
+ FREE(feature_tag_list_buffer);
+ }
+ }
+ }
+
+ return true;
+}
+
+HB_Bool HB_OpenTypeShape(HB_ShaperItem *item, const hb_uint32 *properties)
+{
+
+ HB_Face face = item->face;
+
+ face->length = item->num_glyphs;
+
+ hb_buffer_clear(face->buffer);
+
+ face->tmpAttributes = (HB_GlyphAttributes *) realloc(face->tmpAttributes, face->length*sizeof(HB_GlyphAttributes));
+ face->tmpLogClusters = (unsigned int *) realloc(face->tmpLogClusters, face->length*sizeof(unsigned int));
+ for (int i = 0; i < face->length; ++i) {
+ hb_buffer_add_glyph(face->buffer, item->glyphs[i], properties ? properties[i] : 0, i);
+ face->tmpAttributes[i] = item->attributes[i];
+ face->tmpLogClusters[i] = item->log_clusters[i];
+ }
+
+#ifdef OT_DEBUG
+ DEBUG("-----------------------------------------");
+// DEBUG("log clusters before shaping:");
+// for (int j = 0; j < length; j++)
+// DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
+ DEBUG("original glyphs: %p", item->glyphs);
+ for (int i = 0; i < length; ++i)
+ DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
+// dump_string(hb_buffer);
+#endif
+
+ face->glyphs_substituted = false;
+ if (face->gsub) {
+ unsigned int error = HB_GSUB_Apply_String(face->gsub, face->buffer);
+ if (error && error != HB_Err_Not_Covered)
+ return false;
+ face->glyphs_substituted = (error != HB_Err_Not_Covered);
+ }
+
+#ifdef OT_DEBUG
+// DEBUG("log clusters before shaping:");
+// for (int j = 0; j < length; j++)
+// DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
+ DEBUG("shaped glyphs:");
+ for (int i = 0; i < length; ++i)
+ DEBUG(" glyph=%4x", hb_buffer->in_string[i].gindex);
+ DEBUG("-----------------------------------------");
+// dump_string(hb_buffer);
+#endif
+
+ return true;
+}
+
+HB_Bool HB_OpenTypePosition(HB_ShaperItem *item, int availableGlyphs, HB_Bool doLogClusters)
+{
+ HB_Face face = item->face;
+
+ bool glyphs_positioned = false;
+ if (face->gpos) {
+ if (face->buffer->positions)
+ memset(face->buffer->positions, 0, face->buffer->in_length*sizeof(HB_PositionRec));
+ // #### check that passing "false,false" is correct
+ glyphs_positioned = HB_GPOS_Apply_String(item->font, face->gpos, face->current_flags, face->buffer, false, false) != HB_Err_Not_Covered;
+ }
+
+ if (!face->glyphs_substituted && !glyphs_positioned) {
+ HB_GetGlyphAdvances(item);
+ return true; // nothing to do for us
+ }
+
+ // make sure we have enough space to write everything back
+ if (availableGlyphs < (int)face->buffer->in_length) {
+ item->num_glyphs = face->buffer->in_length;
+ return false;
+ }
+
+ HB_Glyph *glyphs = item->glyphs;
+ HB_GlyphAttributes *attributes = item->attributes;
+
+ for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
+ glyphs[i] = face->buffer->in_string[i].gindex;
+ attributes[i] = face->tmpAttributes[face->buffer->in_string[i].cluster];
+ if (i && face->buffer->in_string[i].cluster == face->buffer->in_string[i-1].cluster)
+ attributes[i].clusterStart = false;
+ }
+ item->num_glyphs = face->buffer->in_length;
+
+ if (doLogClusters && face->glyphs_substituted) {
+ // we can't do this for indic, as we pass the stuf in syllables and it's easier to do it in the shaper.
+ unsigned short *logClusters = item->log_clusters;
+ int clusterStart = 0;
+ int oldCi = 0;
+ // #### the reconstruction of the logclusters currently does not work if the original string
+ // contains surrogate pairs
+ for (unsigned int i = 0; i < face->buffer->in_length; ++i) {
+ int ci = face->buffer->in_string[i].cluster;
+ // DEBUG(" ci[%d] = %d mark=%d, cmb=%d, cs=%d",
+ // i, ci, glyphAttributes[i].mark, glyphAttributes[i].combiningClass, glyphAttributes[i].clusterStart);
+ if (!attributes[i].mark && attributes[i].clusterStart && ci != oldCi) {
+ for (int j = oldCi; j < ci; j++)
+ logClusters[j] = clusterStart;
+ clusterStart = i;
+ oldCi = ci;
+ }
+ }
+ for (int j = oldCi; j < face->length; j++)
+ logClusters[j] = clusterStart;
+ }
+
+ // calulate the advances for the shaped glyphs
+// DEBUG("unpositioned: ");
+
+ // positioning code:
+ if (glyphs_positioned) {
+ HB_GetGlyphAdvances(item);
+ HB_Position positions = face->buffer->positions;
+ HB_Fixed *advances = item->advances;
+
+// DEBUG("positioned glyphs:");
+ for (unsigned int i = 0; i < face->buffer->in_length; i++) {
+// DEBUG(" %d:\t orig advance: (%d/%d)\tadv=(%d/%d)\tpos=(%d/%d)\tback=%d\tnew_advance=%d", i,
+// glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
+// (int)(positions[i].x_advance >> 6), (int)(positions[i].y_advance >> 6),
+// (int)(positions[i].x_pos >> 6), (int)(positions[i].y_pos >> 6),
+// positions[i].back, positions[i].new_advance);
+
+ HB_Fixed adjustment = (item->item.bidiLevel % 2) ? -positions[i].x_advance : positions[i].x_advance;
+
+ if (!(face->current_flags & HB_ShaperFlag_UseDesignMetrics))
+ adjustment = HB_FIXED_ROUND(adjustment);
+
+ if (positions[i].new_advance) {
+ advances[i] = adjustment;
+ } else {
+ advances[i] += adjustment;
+ }
+
+ int back = 0;
+ HB_FixedPoint *offsets = item->offsets;
+ offsets[i].x = positions[i].x_pos;
+ offsets[i].y = positions[i].y_pos;
+ while (positions[i - back].back) {
+ back += positions[i - back].back;
+ offsets[i].x += positions[i - back].x_pos;
+ offsets[i].y += positions[i - back].y_pos;
+ }
+ offsets[i].y = -offsets[i].y;
+
+ if (item->item.bidiLevel % 2) {
+ // ### may need to go back multiple glyphs like in ltr
+ back = positions[i].back;
+ while (back--)
+ offsets[i].x -= advances[i-back];
+ } else {
+ back = 0;
+ while (positions[i - back].back) {
+ back += positions[i - back].back;
+ offsets[i].x -= advances[i-back];
+ }
+ }
+// DEBUG(" ->\tadv=%d\tpos=(%d/%d)",
+// glyphs[i].advance.x.toInt(), glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
+ }
+ item->kerning_applied = face->has_opentype_kerning;
+ } else {
+ HB_HeuristicPosition(item);
+ }
+
+#ifdef OT_DEBUG
+ if (doLogClusters) {
+ DEBUG("log clusters after shaping:");
+ for (int j = 0; j < length; j++)
+ DEBUG(" log[%d] = %d", j, item->log_clusters[j]);
+ }
+ DEBUG("final glyphs:");
+ for (int i = 0; i < (int)hb_buffer->in_length; ++i)
+ DEBUG(" glyph=%4x char_index=%d mark: %d cmp: %d, clusterStart: %d advance=%d/%d offset=%d/%d",
+ glyphs[i].glyph, hb_buffer->in_string[i].cluster, glyphs[i].attributes.mark,
+ glyphs[i].attributes.combiningClass, glyphs[i].attributes.clusterStart,
+ glyphs[i].advance.x.toInt(), glyphs[i].advance.y.toInt(),
+ glyphs[i].offset.x.toInt(), glyphs[i].offset.y.toInt());
+ DEBUG("-----------------------------------------");
+#endif
+ return true;
+}
+
+HB_Bool HB_ShapeItem(HB_ShaperItem *shaper_item)
+{
+ HB_Bool result = false;
+ if (shaper_item->num_glyphs < shaper_item->item.length) {
+ shaper_item->num_glyphs = shaper_item->item.length;
+ return false;
+ }
+ assert(shaper_item->item.script < HB_ScriptCount);
+ result = HB_ScriptEngines[shaper_item->item.script].shape(shaper_item);
+ shaper_item->glyphIndicesPresent = false;
+ return result;
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-shaper.h b/third_party/harfbuzz/src/harfbuzz-shaper.h
new file mode 100644
index 0000000..1577b59
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-shaper.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_SHAPER_H
+#define HARFBUZZ_SHAPER_H
+
+#include "harfbuzz-global.h"
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-gpos.h"
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-external.h"
+#include "harfbuzz-stream-private.h"
+
+HB_BEGIN_HEADER
+
+typedef enum {
+ HB_Script_Common,
+ HB_Script_Greek,
+ HB_Script_Cyrillic,
+ HB_Script_Armenian,
+ HB_Script_Hebrew,
+ HB_Script_Arabic,
+ HB_Script_Syriac,
+ HB_Script_Thaana,
+ HB_Script_Devanagari,
+ HB_Script_Bengali,
+ HB_Script_Gurmukhi,
+ HB_Script_Gujarati,
+ HB_Script_Oriya,
+ HB_Script_Tamil,
+ HB_Script_Telugu,
+ HB_Script_Kannada,
+ HB_Script_Malayalam,
+ HB_Script_Sinhala,
+ HB_Script_Thai,
+ HB_Script_Lao,
+ HB_Script_Tibetan,
+ HB_Script_Myanmar,
+ HB_Script_Georgian,
+ HB_Script_Hangul,
+ HB_Script_Ogham,
+ HB_Script_Runic,
+ HB_Script_Khmer,
+ HB_Script_Inherited,
+ HB_ScriptCount = HB_Script_Inherited
+ /*
+ HB_Script_Latin = Common,
+ HB_Script_Ethiopic = Common,
+ HB_Script_Cherokee = Common,
+ HB_Script_CanadianAboriginal = Common,
+ HB_Script_Mongolian = Common,
+ HB_Script_Hiragana = Common,
+ HB_Script_Katakana = Common,
+ HB_Script_Bopomofo = Common,
+ HB_Script_Han = Common,
+ HB_Script_Yi = Common,
+ HB_Script_OldItalic = Common,
+ HB_Script_Gothic = Common,
+ HB_Script_Deseret = Common,
+ HB_Script_Tagalog = Common,
+ HB_Script_Hanunoo = Common,
+ HB_Script_Buhid = Common,
+ HB_Script_Tagbanwa = Common,
+ HB_Script_Limbu = Common,
+ HB_Script_TaiLe = Common,
+ HB_Script_LinearB = Common,
+ HB_Script_Ugaritic = Common,
+ HB_Script_Shavian = Common,
+ HB_Script_Osmanya = Common,
+ HB_Script_Cypriot = Common,
+ HB_Script_Braille = Common,
+ HB_Script_Buginese = Common,
+ HB_Script_Coptic = Common,
+ HB_Script_NewTaiLue = Common,
+ HB_Script_Glagolitic = Common,
+ HB_Script_Tifinagh = Common,
+ HB_Script_SylotiNagri = Common,
+ HB_Script_OldPersian = Common,
+ HB_Script_Kharoshthi = Common,
+ HB_Script_Balinese = Common,
+ HB_Script_Cuneiform = Common,
+ HB_Script_Phoenician = Common,
+ HB_Script_PhagsPa = Common,
+ HB_Script_Nko = Common
+ */
+} HB_Script;
+
+typedef struct
+{
+ hb_uint32 pos;
+ hb_uint32 length;
+ HB_Script script;
+ hb_uint8 bidiLevel;
+} HB_ScriptItem;
+
+typedef enum {
+ HB_NoBreak,
+ HB_SoftHyphen,
+ HB_Break,
+ HB_ForcedBreak
+} HB_LineBreakType;
+
+
+typedef struct {
+ /*HB_LineBreakType*/ unsigned lineBreakType :2;
+ /*HB_Bool*/ unsigned whiteSpace :1; /* A unicode whitespace character, except NBSP, ZWNBSP */
+ /*HB_Bool*/ unsigned charStop :1; /* Valid cursor position (for left/right arrow) */
+ /*HB_Bool*/ unsigned wordBoundary :1;
+ /*HB_Bool*/ unsigned sentenceBoundary :1;
+ unsigned unused :2;
+} HB_CharAttributes;
+
+void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem *items, hb_uint32 numItems,
+ HB_CharAttributes *attributes);
+
+/* requires HB_GetCharAttributes to be called before */
+void HB_GetWordBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem *items, hb_uint32 numItems,
+ HB_CharAttributes *attributes);
+
+/* requires HB_GetCharAttributes to be called before */
+void HB_GetSentenceBoundaries(const HB_UChar16 *string, hb_uint32 stringLength,
+ const HB_ScriptItem *items, hb_uint32 numItems,
+ HB_CharAttributes *attributes);
+
+
+typedef enum {
+ HB_LeftToRight = 0,
+ HB_RightToLeft = 1
+} HB_StringToGlyphsFlags;
+
+typedef enum {
+ HB_ShaperFlag_Default = 0,
+ HB_ShaperFlag_NoKerning = 1,
+ HB_ShaperFlag_UseDesignMetrics = 2
+} HB_ShaperFlag;
+
+/*
+ highest value means highest priority for justification. Justification is done by first inserting kashidas
+ starting with the highest priority positions, then stretching spaces, afterwards extending inter char
+ spacing, and last spacing between arabic words.
+ NoJustification is for example set for arabic where no Kashida can be inserted or for diacritics.
+*/
+typedef enum {
+ HB_NoJustification= 0, /* Justification can't be applied after this glyph */
+ HB_Arabic_Space = 1, /* This glyph represents a space inside arabic text */
+ HB_Character = 2, /* Inter-character justification point follows this glyph */
+ HB_Space = 4, /* This glyph represents a blank outside an Arabic run */
+ HB_Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */
+ HB_Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */
+ HB_Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */
+ HB_Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */
+ HB_Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */
+ HB_Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */
+ HB_Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */
+} HB_JustificationClass;
+
+/* This structure is binary compatible with Uniscribe's SCRIPT_VISATTR. Would be nice to keep
+ * it like that. If this is a problem please tell Trolltech :)
+ */
+typedef struct {
+ unsigned justification :4; /* Justification class */
+ unsigned clusterStart :1; /* First glyph of representation of cluster */
+ unsigned mark :1; /* needs to be positioned around base char */
+ unsigned zeroWidth :1; /* ZWJ, ZWNJ etc, with no width */
+ unsigned dontPrint :1;
+ unsigned combiningClass :8;
+} HB_GlyphAttributes;
+
+typedef struct HB_FaceRec_ {
+ HB_Bool isSymbolFont;
+
+ HB_GDEF gdef;
+ HB_GSUB gsub;
+ HB_GPOS gpos;
+ HB_Bool supported_scripts[HB_ScriptCount];
+ HB_Buffer buffer;
+ HB_Script current_script;
+ int current_flags; /* HB_ShaperFlags */
+ HB_Bool has_opentype_kerning;
+ HB_Bool glyphs_substituted;
+ HB_GlyphAttributes *tmpAttributes;
+ unsigned int *tmpLogClusters;
+ int length;
+ int orig_nglyphs;
+} HB_FaceRec;
+
+typedef HB_Error (*HB_GetFontTableFunc)(void *font, HB_Tag tag, HB_Byte *buffer, HB_UInt *length);
+
+HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc);
+void HB_FreeFace(HB_Face face);
+
+typedef struct {
+ HB_Fixed x, y;
+ HB_Fixed width, height;
+ HB_Fixed xOffset, yOffset;
+} HB_GlyphMetrics;
+
+typedef enum {
+ HB_FontAscent
+} HB_FontMetric;
+
+typedef struct {
+ HB_Bool (*convertStringToGlyphIndices)(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft);
+ void (*getGlyphAdvances)(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags /*HB_ShaperFlag*/);
+ HB_Bool (*canRender)(HB_Font font, const HB_UChar16 *string, hb_uint32 length);
+ /* implementation needs to make sure to load a scaled glyph, so /no/ FT_LOAD_NO_SCALE */
+ HB_Error (*getPointInOutline)(HB_Font font, HB_Glyph glyph, int flags /*HB_ShaperFlag*/, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints);
+ void (*getGlyphMetrics)(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics);
+ HB_Fixed (*getFontMetric)(HB_Font font, HB_FontMetric metric);
+} HB_FontClass;
+
+typedef struct HB_Font_ {
+ const HB_FontClass *klass;
+
+ /* Metrics */
+ HB_UShort x_ppem, y_ppem;
+ HB_16Dot16 x_scale, y_scale;
+
+ void *userData;
+} HB_FontRec;
+
+typedef struct HB_ShaperItem_ HB_ShaperItem;
+
+struct HB_ShaperItem_ {
+ const HB_UChar16 *string;
+ hb_uint32 stringLength;
+ HB_ScriptItem item;
+ HB_Font font;
+ HB_Face face;
+ int shaperFlags; /* HB_ShaperFlags */
+
+ HB_Bool glyphIndicesPresent; /* set to true if the glyph indicies are already setup in the glyphs array */
+ hb_uint32 initialGlyphCount;
+
+ hb_uint32 num_glyphs; /* in: available glyphs out: glyphs used/needed */
+ HB_Glyph *glyphs; /* out parameter */
+ HB_GlyphAttributes *attributes; /* out */
+ HB_Fixed *advances; /* out */
+ HB_FixedPoint *offsets; /* out */
+ unsigned short *log_clusters; /* out */
+
+ /* internal */
+ HB_Bool kerning_applied; /* out: kerning applied by shaper */
+};
+
+HB_Bool HB_ShapeItem(HB_ShaperItem *item);
+
+HB_END_HEADER
+
+#endif
diff --git a/third_party/harfbuzz/src/harfbuzz-stream-private.h b/third_party/harfbuzz/src/harfbuzz-stream-private.h
new file mode 100644
index 0000000..fbd9f81
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-stream-private.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_STREAM_PRIVATE_H
+#define HARFBUZZ_STREAM_PRIVATE_H
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-stream.h"
+
+HB_BEGIN_HEADER
+
+HB_INTERNAL void
+_hb_close_stream( HB_Stream stream );
+
+HB_INTERNAL HB_Int
+_hb_stream_pos( HB_Stream stream );
+
+HB_INTERNAL HB_Error
+_hb_stream_seek( HB_Stream stream,
+ HB_UInt pos );
+
+HB_INTERNAL HB_Error
+_hb_stream_frame_enter( HB_Stream stream,
+ HB_UInt size );
+
+HB_INTERNAL void
+_hb_stream_frame_exit( HB_Stream stream );
+
+/* convenience macros */
+
+#define SET_ERR(c) ( (error = (c)) != 0 )
+
+#define GOTO_Table(tag) (0)
+#define FILE_Pos() _hb_stream_pos( stream )
+#define FILE_Seek(pos) SET_ERR( _hb_stream_seek( stream, pos ) )
+#define ACCESS_Frame(size) SET_ERR( _hb_stream_frame_enter( stream, size ) )
+#define FORGET_Frame() _hb_stream_frame_exit( stream )
+
+#define GET_Byte() (*stream->cursor++)
+#define GET_Short() (stream->cursor += 2, (HB_Short)( \
+ (*(((HB_Byte*)stream->cursor)-2) << 8) | \
+ *(((HB_Byte*)stream->cursor)-1) \
+ ))
+#define GET_Long() (stream->cursor += 4, (HB_Int)( \
+ (*(((HB_Byte*)stream->cursor)-4) << 24) | \
+ (*(((HB_Byte*)stream->cursor)-3) << 16) | \
+ (*(((HB_Byte*)stream->cursor)-2) << 8) | \
+ *(((HB_Byte*)stream->cursor)-1) \
+ ))
+
+
+#define GET_Char() ((HB_Char)GET_Byte())
+#define GET_UShort() ((HB_UShort)GET_Short())
+#define GET_ULong() ((HB_UInt)GET_Long())
+#define GET_Tag4() GET_ULong()
+
+HB_END_HEADER
+
+#endif /* HARFBUZZ_STREAM_PRIVATE_H */
diff --git a/third_party/harfbuzz/src/harfbuzz-stream.c b/third_party/harfbuzz/src/harfbuzz-stream.c
new file mode 100644
index 0000000..3dcee82
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-stream.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2005 David Turner
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#include "harfbuzz-impl.h"
+#include "harfbuzz-stream-private.h"
+#include <stdlib.h>
+
+#if 0
+#include <stdio.h>
+#define LOG(x) _hb_log x
+
+static void
+_hb_log( const char* format, ... )
+{
+ va_list ap;
+
+ va_start( ap, format );
+ vfprintf( stderr, format, ap );
+ va_end( ap );
+}
+
+#else
+#define LOG(x) do {} while (0)
+#endif
+
+HB_INTERNAL void
+_hb_close_stream( HB_Stream stream )
+{
+ if (!stream)
+ return;
+ free(stream->base);
+ free(stream);
+}
+
+
+HB_INTERNAL HB_Int
+_hb_stream_pos( HB_Stream stream )
+{
+ LOG(( "_hb_stream_pos() -> %ld\n", stream->pos ));
+ return stream->pos;
+}
+
+
+HB_INTERNAL HB_Error
+_hb_stream_seek( HB_Stream stream,
+ HB_UInt pos )
+{
+ HB_Error error = 0;
+
+ stream->pos = pos;
+ if (pos > stream->size)
+ error = ERR(HB_Err_Read_Error);
+
+ LOG(( "_hb_stream_seek(%ld) -> 0x%04X\n", pos, error ));
+ return error;
+}
+
+
+HB_INTERNAL HB_Error
+_hb_stream_frame_enter( HB_Stream stream,
+ HB_UInt count )
+{
+ HB_Error error = HB_Err_Ok;
+
+ /* check new position, watch for overflow */
+ if (HB_UNLIKELY (stream->pos + count > stream->size ||
+ stream->pos + count < stream->pos))
+ {
+ error = ERR(HB_Err_Read_Error);
+ goto Exit;
+ }
+
+ /* set cursor */
+ stream->cursor = stream->base + stream->pos;
+ stream->pos += count;
+
+Exit:
+ LOG(( "_hb_stream_frame_enter(%ld) -> 0x%04X\n", count, error ));
+ return error;
+}
+
+
+HB_INTERNAL void
+_hb_stream_frame_exit( HB_Stream stream )
+{
+ stream->cursor = NULL;
+
+ LOG(( "_hb_stream_frame_exit()\n" ));
+}
diff --git a/third_party/harfbuzz/src/harfbuzz-stream.h b/third_party/harfbuzz/src/harfbuzz-stream.h
new file mode 100644
index 0000000..9991936
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-stream.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2005 David Turner
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_STREAM_H
+#define HARFBUZZ_STREAM_H
+
+#include "harfbuzz-global.h"
+
+HB_BEGIN_HEADER
+
+typedef struct HB_StreamRec_
+{
+ HB_Byte* base;
+ HB_UInt size;
+ HB_UInt pos;
+
+ HB_Byte* cursor;
+} HB_StreamRec;
+
+
+HB_END_HEADER
+
+#endif
diff --git a/third_party/harfbuzz/src/harfbuzz-thai.c b/third_party/harfbuzz/src/harfbuzz-thai.c
new file mode 100644
index 0000000..1d1aa2f
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-thai.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+#include "harfbuzz-external.h"
+
+#include <assert.h>
+
+static void thaiWordBreaks(const HB_UChar16 *string, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ typedef int (*th_brk_def)(const char*, int[], int);
+ static void *thaiCodec = 0;
+ static th_brk_def th_brk = 0;
+ char *cstr = 0;
+ int brp[128];
+ int *break_positions = brp;
+ hb_uint32 numbreaks;
+ hb_uint32 i;
+
+ if (!thaiCodec)
+ thaiCodec = HB_TextCodecForMib(2259);
+
+ /* load libthai dynamically */
+ if (!th_brk && thaiCodec) {
+ th_brk = (th_brk_def)HB_Library_Resolve("thai", "th_brk");
+ if (!th_brk)
+ thaiCodec = 0;
+ }
+
+ if (!th_brk)
+ return;
+
+ cstr = HB_TextCodec_ConvertFromUnicode(thaiCodec, string, len, 0);
+ if (!cstr)
+ return;
+
+ break_positions = brp;
+ numbreaks = th_brk(cstr, break_positions, 128);
+ if (numbreaks > 128) {
+ break_positions = (int *)malloc(numbreaks * sizeof(int));
+ numbreaks = th_brk(cstr, break_positions, numbreaks);
+ }
+
+ for (i = 0; i < len; ++i)
+ attributes[i].lineBreakType = HB_NoBreak;
+
+ for (i = 0; i < numbreaks; ++i) {
+ if (break_positions[i] > 0)
+ attributes[break_positions[i]-1].lineBreakType = HB_Break;
+ }
+
+ if (break_positions != brp)
+ free(break_positions);
+
+ HB_TextCodec_FreeResult(cstr);
+}
+
+
+void HB_ThaiAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ assert(script == HB_Script_Thai);
+ attributes += from;
+ thaiWordBreaks(text + from, len, attributes);
+}
+
diff --git a/third_party/harfbuzz/src/harfbuzz-tibetan.c b/third_party/harfbuzz/src/harfbuzz-tibetan.c
new file mode 100644
index 0000000..bfa31b1d
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz-tibetan.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-shaper-private.h"
+
+#include <assert.h>
+
+/*
+ tibetan syllables are of the form:
+ head position consonant
+ first sub-joined consonant
+ ....intermediate sub-joined consonants (if any)
+ last sub-joined consonant
+ sub-joined vowel (a-chung U+0F71)
+ standard or compound vowel sign (or 'virama' for devanagari transliteration)
+*/
+
+typedef enum {
+ TibetanOther,
+ TibetanHeadConsonant,
+ TibetanSubjoinedConsonant,
+ TibetanSubjoinedVowel,
+ TibetanVowel
+} TibetanForm;
+
+/* this table starts at U+0f40 */
+static const unsigned char tibetanForm[0x80] = {
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant, TibetanHeadConsonant,
+ TibetanOther, TibetanOther, TibetanOther, TibetanOther,
+
+ TibetanOther, TibetanVowel, TibetanVowel, TibetanVowel,
+ TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
+ TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
+ TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
+
+ TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
+ TibetanVowel, TibetanVowel, TibetanVowel, TibetanVowel,
+ TibetanOther, TibetanOther, TibetanOther, TibetanOther,
+ TibetanOther, TibetanOther, TibetanOther, TibetanOther,
+
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant, TibetanSubjoinedConsonant,
+ TibetanSubjoinedConsonant, TibetanOther, TibetanOther, TibetanOther
+};
+
+
+#define tibetan_form(c) \
+ (TibetanForm)tibetanForm[c - 0x0f40]
+
+static const HB_OpenTypeFeature tibetan_features[] = {
+ { HB_MAKE_TAG('c', 'c', 'm', 'p'), CcmpProperty },
+ { HB_MAKE_TAG('a', 'b', 'v', 's'), AboveSubstProperty },
+ { HB_MAKE_TAG('b', 'l', 'w', 's'), BelowSubstProperty },
+ { HB_MAKE_TAG('c', 'a', 'l', 't'), CaltProperty },
+ {0, 0}
+};
+
+static HB_Bool tibetan_shape_syllable(HB_Bool openType, HB_ShaperItem *item, HB_Bool invalid)
+{
+ hb_uint32 i;
+ const HB_UChar16 *str = item->string + item->item.pos;
+ int len = item->item.length;
+#ifndef NO_OPENTYPE
+ const int availableGlyphs = item->num_glyphs;
+#endif
+ HB_Bool haveGlyphs;
+ HB_STACKARRAY(HB_UChar16, reordered, len + 4);
+
+ if (item->num_glyphs < item->item.length + 4) {
+ item->num_glyphs = item->item.length + 4;
+ return FALSE;
+ }
+
+ if (invalid) {
+ *reordered = 0x25cc;
+ memcpy(reordered+1, str, len*sizeof(HB_UChar16));
+ len++;
+ str = reordered;
+ }
+
+ haveGlyphs = item->font->klass->convertStringToGlyphIndices(item->font,
+ str, len,
+ item->glyphs, &item->num_glyphs,
+ item->item.bidiLevel % 2);
+
+ HB_FREE_STACKARRAY(reordered);
+
+ if (!haveGlyphs)
+ return FALSE;
+
+ for (i = 0; i < item->item.length; i++) {
+ item->attributes[i].mark = FALSE;
+ item->attributes[i].clusterStart = FALSE;
+ item->attributes[i].justification = 0;
+ item->attributes[i].zeroWidth = FALSE;
+/* IDEBUG(" %d: %4x", i, str[i]); */
+ }
+
+ /* now we have the syllable in the right order, and can start running it through open type. */
+
+#ifndef NO_OPENTYPE
+ if (openType) {
+ HB_OpenTypeShape(item, /*properties*/0);
+ if (!HB_OpenTypePosition(item, availableGlyphs, /*doLogClusters*/FALSE))
+ return FALSE;
+ } else {
+ HB_HeuristicPosition(item);
+ }
+#endif
+
+ item->attributes[0].clusterStart = TRUE;
+ return TRUE;
+}
+
+
+static int tibetan_nextSyllableBoundary(const HB_UChar16 *s, int start, int end, HB_Bool *invalid)
+{
+ const HB_UChar16 *uc = s + start;
+
+ int pos = 0;
+ TibetanForm state = tibetan_form(*uc);
+
+/* qDebug("state[%d]=%d (uc=%4x)", pos, state, uc[pos]);*/
+ pos++;
+
+ if (state != TibetanHeadConsonant) {
+ if (state != TibetanOther)
+ *invalid = TRUE;
+ goto finish;
+ }
+
+ while (pos < end - start) {
+ TibetanForm newState = tibetan_form(uc[pos]);
+ switch(newState) {
+ case TibetanSubjoinedConsonant:
+ case TibetanSubjoinedVowel:
+ if (state != TibetanHeadConsonant &&
+ state != TibetanSubjoinedConsonant)
+ goto finish;
+ state = newState;
+ break;
+ case TibetanVowel:
+ if (state != TibetanHeadConsonant &&
+ state != TibetanSubjoinedConsonant &&
+ state != TibetanSubjoinedVowel)
+ goto finish;
+ break;
+ case TibetanOther:
+ case TibetanHeadConsonant:
+ goto finish;
+ }
+ pos++;
+ }
+
+finish:
+ *invalid = FALSE;
+ return start+pos;
+}
+
+HB_Bool HB_TibetanShape(HB_ShaperItem *item)
+{
+
+ HB_Bool openType = FALSE;
+ unsigned short *logClusters = item->log_clusters;
+
+ HB_ShaperItem syllable = *item;
+ int first_glyph = 0;
+
+ int sstart = item->item.pos;
+ int end = sstart + item->item.length;
+
+ assert(item->item.script == HB_Script_Tibetan);
+
+#ifndef QT_NO_OPENTYPE
+ openType = HB_SelectScript(item, tibetan_features);
+#endif
+
+ while (sstart < end) {
+ HB_Bool invalid;
+ int i;
+ int send = tibetan_nextSyllableBoundary(item->string, sstart, end, &invalid);
+/* IDEBUG("syllable from %d, length %d, invalid=%s", sstart, send-sstart,
+ invalid ? "TRUE" : "FALSE"); */
+ syllable.item.pos = sstart;
+ syllable.item.length = send-sstart;
+ syllable.glyphs = item->glyphs + first_glyph;
+ syllable.attributes = item->attributes + first_glyph;
+ syllable.offsets = item->offsets + first_glyph;
+ syllable.advances = item->advances + first_glyph;
+ syllable.num_glyphs = item->num_glyphs - first_glyph;
+ if (!tibetan_shape_syllable(openType, &syllable, invalid)) {
+ item->num_glyphs += syllable.num_glyphs;
+ return FALSE;
+ }
+ /* fix logcluster array */
+ for (i = sstart; i < send; ++i)
+ logClusters[i-item->item.pos] = first_glyph;
+ sstart = send;
+ first_glyph += syllable.num_glyphs;
+ }
+ item->num_glyphs = first_glyph;
+ return TRUE;
+}
+
+void HB_TibetanAttributes(HB_Script script, const HB_UChar16 *text, hb_uint32 from, hb_uint32 len, HB_CharAttributes *attributes)
+{
+ int end = from + len;
+ const HB_UChar16 *uc = text + from;
+ hb_uint32 i = 0;
+ HB_UNUSED(script);
+ attributes += from;
+ while (i < len) {
+ HB_Bool invalid;
+ hb_uint32 boundary = tibetan_nextSyllableBoundary(text, from+i, end, &invalid) - from;
+
+ attributes[i].charStop = TRUE;
+
+ if (boundary > len-1) boundary = len;
+ i++;
+ while (i < boundary) {
+ attributes[i].charStop = FALSE;
+ ++uc;
+ ++i;
+ }
+ assert(i == boundary);
+ }
+}
+
+
diff --git a/third_party/harfbuzz/src/harfbuzz.c b/third_party/harfbuzz/src/harfbuzz.c
new file mode 100644
index 0000000..3e4a30a
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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_INTERNAL static
+#include "harfbuzz-buffer.c"
+#include "harfbuzz-gdef.c"
+#include "harfbuzz-gsub.c"
+#include "harfbuzz-gpos.c"
+#include "harfbuzz-impl.c"
+#include "harfbuzz-open.c"
+#include "harfbuzz-stream.c"
diff --git a/third_party/harfbuzz/src/harfbuzz.h b/third_party/harfbuzz/src/harfbuzz.h
new file mode 100644
index 0000000..e91a33e
--- /dev/null
+++ b/third_party/harfbuzz/src/harfbuzz.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2006 Behdad Esfahbod
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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 HARFBUZZ_H
+#define HARFBUZZ_H
+
+#include "harfbuzz-external.h"
+#include "harfbuzz-global.h"
+#include "harfbuzz-buffer.h"
+#include "harfbuzz-gdef.h"
+#include "harfbuzz-gsub.h"
+#include "harfbuzz-gpos.h"
+#include "harfbuzz-open.h"
+#include "harfbuzz-shaper.h"
+
+#endif /* HARFBUZZ_OPEN_H */
diff --git a/third_party/harfbuzz/tests/Makefile.am b/third_party/harfbuzz/tests/Makefile.am
new file mode 100644
index 0000000..febf890
--- /dev/null
+++ b/third_party/harfbuzz/tests/Makefile.am
@@ -0,0 +1,7 @@
+
+SUBDIRS =
+
+if QT
+SUBDIRS += linebreaking shaping
+endif
+
diff --git a/third_party/harfbuzz/tests/linebreaking/.gitignore b/third_party/harfbuzz/tests/linebreaking/.gitignore
new file mode 100644
index 0000000..81e019d
--- /dev/null
+++ b/third_party/harfbuzz/tests/linebreaking/.gitignore
@@ -0,0 +1,4 @@
+.deps
+linebreaking
+*.moc
+*.o
diff --git a/third_party/harfbuzz/tests/linebreaking/Makefile.am b/third_party/harfbuzz/tests/linebreaking/Makefile.am
new file mode 100644
index 0000000..b710896
--- /dev/null
+++ b/third_party/harfbuzz/tests/linebreaking/Makefile.am
@@ -0,0 +1,12 @@
+
+check_PROGRAMS = linebreaking
+
+linebreaking_SOURCES = main.cpp harfbuzz-qt.cpp
+linebreaking_LDADD = $(QT_GUI_LIBS) $(QT_QTEST_LIBS) ../../src/libharfbuzz-1.la
+
+main.o: main.moc
+
+main.moc: $(srcdir)/main.cpp
+ $(QT_MOC) -o main.moc $(srcdir)/main.cpp
+
+INCLUDES = -I$(top_srcdir)/src $(FREETYPE_CFLAGS) $(QT_GUI_CFLAGS) $(QT_QTEST_CFLAGS)
diff --git a/third_party/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp b/third_party/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp
new file mode 100644
index 0000000..ea03052
--- /dev/null
+++ b/third_party/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include <harfbuzz-external.h>
+#include <Qt/private/qunicodetables_p.h>
+#include <QLibrary>
+#include <QTextCodec>
+
+extern "C" {
+
+HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch)
+{
+#if QT_VERSION >= 0x040300
+ return (HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch);
+#else
+#error "This test currently requires Qt >= 4.3"
+#endif
+}
+
+void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass)
+{
+ *category = (HB_CharCategory)QChar::category(ch);
+ *combiningClass = QChar::combiningClass(ch);
+}
+
+HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch)
+{
+ return (HB_CharCategory)QChar::category(ch);
+}
+
+int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch)
+{
+ return QChar::combiningClass(ch);
+}
+
+HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch)
+{
+ return QChar::mirroredChar(ch);
+}
+
+HB_WordClass HB_GetWordClass(HB_UChar32 ch)
+{
+ const QUnicodeTables::Properties *prop = QUnicodeTables::properties(ch);
+ return (HB_WordClass) prop->wordBreak;
+}
+
+
+HB_SentenceClass HB_GetSentenceClass(HB_UChar32 ch)
+{
+ const QUnicodeTables::Properties *prop = QUnicodeTables::properties(ch);
+ return (HB_SentenceClass) prop->sentenceBreak;
+}
+
+void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme, HB_LineBreakClass *lineBreak)
+{
+ const QUnicodeTables::Properties *prop = QUnicodeTables::properties(ch);
+ *grapheme = (HB_GraphemeClass) prop->graphemeBreak;
+ *lineBreak = (HB_LineBreakClass) prop->line_break_class;
+}
+
+void *HB_Library_Resolve(const char *library, const char *symbol)
+{
+ return QLibrary::resolve(library, symbol);
+}
+
+void *HB_TextCodecForMib(int mib)
+{
+ return QTextCodec::codecForMib(mib);
+}
+
+char *HB_TextCodec_ConvertFromUnicode(void *codec, const HB_UChar16 *unicode, hb_uint32 length, hb_uint32 *outputLength)
+{
+ QByteArray data = reinterpret_cast<QTextCodec *>(codec)->fromUnicode((const QChar *)unicode, length);
+ // ### suboptimal
+ char *output = (char *)malloc(data.length() + 1);
+ memcpy(output, data.constData(), data.length() + 1);
+ if (outputLength)
+ *outputLength = data.length();
+ return output;
+}
+
+void HB_TextCodec_FreeResult(char *string)
+{
+ free(string);
+}
+
+}
diff --git a/third_party/harfbuzz/tests/linebreaking/main.cpp b/third_party/harfbuzz/tests/linebreaking/main.cpp
new file mode 100644
index 0000000..3b2734a
--- /dev/null
+++ b/third_party/harfbuzz/tests/linebreaking/main.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine 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.
+ */
+
+/*
+ !!!!!! Warning !!!!!
+ Please don't save this file in emacs. It contains utf8 text sequences emacs will
+ silently convert to a series of question marks.
+ */
+#include <QtTest/QtTest>
+#include <QtCore/qdebug.h>
+
+#include <harfbuzz-shaper.h>
+
+static QVector<HB_CharAttributes> getCharAttributes(const QString &str, HB_Script script = HB_Script_Common)
+{
+ QVector<HB_CharAttributes> attrs(str.length());
+ HB_ScriptItem item;
+ item.pos = 0;
+ item.length = str.length();
+ item.script = script;
+ HB_GetCharAttributes(str.utf16(), str.length(),
+ &item, 1,
+ attrs.data());
+ return attrs;
+}
+
+class tst_CharAttributes : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_CharAttributes();
+ virtual ~tst_CharAttributes();
+
+public slots:
+ void init();
+ void cleanup();
+private slots:
+ void lineBreaking();
+ void charWordStopOnLineSeparator();
+ void charStopForSurrogatePairs();
+ void thaiWordBreak();
+};
+
+
+tst_CharAttributes::tst_CharAttributes()
+{
+}
+
+tst_CharAttributes::~tst_CharAttributes()
+{
+}
+
+void tst_CharAttributes::init()
+{
+}
+
+void tst_CharAttributes::cleanup()
+{
+}
+
+
+void tst_CharAttributes::lineBreaking()
+{
+ struct Breaks {
+ const char *utf8;
+ uchar breaks[32];
+ };
+ Breaks brks[] = {
+ { "11", { false, 0xff } },
+ { "aa", { false, 0xff } },
+ { "++", { false, 0xff } },
+ { "--", { false, 0xff } },
+ { "((", { false, 0xff } },
+ { "))", { false, 0xff } },
+ { "..", { false, 0xff } },
+ { "\"\"", { false, 0xff } },
+ { "$$", { false, 0xff } },
+ { "!!", { false, 0xff } },
+ { "??", { false, 0xff } },
+ { ",,", { false, 0xff } },
+
+ { ")()", { true, false, 0xff } },
+ { "?!?", { false, false, 0xff } },
+ { ".,.", { false, false, 0xff } },
+ { "+-+", { false, false, 0xff } },
+ { "+=+", { false, false, 0xff } },
+ { "+(+", { false, false, 0xff } },
+ { "+)+", { false, false, 0xff } },
+
+ { "a b", { false, true, 0xff } },
+ { "a(b", { false, false, 0xff } },
+ { "a)b", { false, false, 0xff } },
+ { "a-b", { false, true, 0xff } },
+ { "a.b", { false, false, 0xff } },
+ { "a+b", { false, false, 0xff } },
+ { "a?b", { false, false, 0xff } },
+ { "a!b", { false, false, 0xff } },
+ { "a$b", { false, false, 0xff } },
+ { "a,b", { false, false, 0xff } },
+ { "a/b", { false, false, 0xff } },
+ { "1/2", { false, false, 0xff } },
+ { "./.", { false, false, 0xff } },
+ { ",/,", { false, false, 0xff } },
+ { "!/!", { false, false, 0xff } },
+ { "\\/\\", { false, false, 0xff } },
+ { "1 2", { false, true, 0xff } },
+ { "1(2", { false, false, 0xff } },
+ { "1)2", { false, false, 0xff } },
+ { "1-2", { false, false, 0xff } },
+ { "1.2", { false, false, 0xff } },
+ { "1+2", { false, false, 0xff } },
+ { "1?2", { false, true, 0xff } },
+ { "1!2", { false, true, 0xff } },
+ { "1$2", { false, false, 0xff } },
+ { "1,2", { false, false, 0xff } },
+ { "1/2", { false, false, 0xff } },
+ { "\330\260\331\216\331\204\331\220\331\203\331\216", { false, false, false, false, false, 0xff } },
+ { "\330\247\331\204\331\205 \330\247\331\204\331\205", { false, false, false, true, false, false, 0xff } },
+ { "1#2", { false, false, 0xff } },
+ { "!#!", { false, false, 0xff } },
+ { 0, {} }
+ };
+ Breaks *b = brks;
+ while (b->utf8) {
+ QString str = QString::fromUtf8(b->utf8);
+
+ QVector<HB_CharAttributes> attrs = getCharAttributes(str);
+
+ int i;
+ for (i = 0; i < (int)str.length() - 1; ++i) {
+ QVERIFY(b->breaks[i] != 0xff);
+ if ( (attrs[i].lineBreakType != HB_NoBreak) != (bool)b->breaks[i] ) {
+ qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i].lineBreakType);
+ QCOMPARE( (attrs[i].lineBreakType != HB_NoBreak), (bool)b->breaks[i] );
+ }
+ }
+ QVERIFY(attrs[i].lineBreakType == HB_ForcedBreak);
+ QCOMPARE(b->breaks[i], (uchar)0xff);
+ ++b;
+ }
+}
+
+void tst_CharAttributes::charWordStopOnLineSeparator()
+{
+ const QChar lineSeparator(QChar::LineSeparator);
+ QString txt;
+ txt.append(lineSeparator);
+ txt.append(lineSeparator);
+ QVector<HB_CharAttributes> attrs = getCharAttributes(txt);
+ QVERIFY(attrs[1].charStop);
+}
+
+void tst_CharAttributes::charStopForSurrogatePairs()
+{
+ QString txt;
+ txt.append("a");
+ txt.append(0xd87e);
+ txt.append(0xdc25);
+ txt.append("b");
+ QVector<HB_CharAttributes> attrs = getCharAttributes(txt);
+ QVERIFY(attrs[0].charStop);
+ QVERIFY(attrs[1].charStop);
+ QVERIFY(!attrs[2].charStop);
+ QVERIFY(attrs[3].charStop);
+}
+
+void tst_CharAttributes::thaiWordBreak()
+{
+ // สวัสดีครับ นี่เป็นการงทดสอบตัวเอ
+ QTextCodec *codec = QTextCodec::codecForMib(2259);
+ QString txt = codec->toUnicode(QByteArray("\xca\xc7\xd1\xca\xb4\xd5\xa4\xc3\xd1\xba\x20\xb9\xd5\xe8\xe0\xbb\xe7\xb9\xa1\xd2\xc3\xb7\xb4\xca\xcd\xba\xb5\xd1\xc7\xe0\xcd\xa7"));
+
+
+ QCOMPARE(txt.length(), 32);
+ QVector<HB_CharAttributes> attrs = getCharAttributes(txt, HB_Script_Thai);
+ QVERIFY(attrs[0].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[1].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[2].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[3].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[4].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[5].lineBreakType == HB_Break);
+ QVERIFY(attrs[6].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[7].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[8].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[9].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[10].lineBreakType == HB_Break);
+ QVERIFY(attrs[11].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[12].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[13].lineBreakType == HB_Break);
+ QVERIFY(attrs[14].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[15].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[16].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[17].lineBreakType == HB_Break);
+ QVERIFY(attrs[18].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[19].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[20].lineBreakType == HB_Break);
+ QVERIFY(attrs[21].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[22].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[23].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[24].lineBreakType == HB_NoBreak);
+ QVERIFY(attrs[25].lineBreakType == HB_Break);
+ QVERIFY(attrs[26].lineBreakType == HB_NoBreak);
+ for (int i = 27; i < 32; ++i)
+ QVERIFY(attrs[i].lineBreakType == HB_NoBreak);
+}
+
+QTEST_MAIN(tst_CharAttributes)
+#include "main.moc"
diff --git a/third_party/harfbuzz/tests/shaping/.gitignore b/third_party/harfbuzz/tests/shaping/.gitignore
new file mode 100644
index 0000000..3f32cbe
--- /dev/null
+++ b/third_party/harfbuzz/tests/shaping/.gitignore
@@ -0,0 +1,2 @@
+harfbuzz-test-fonts-0.1.tar.bz2
+fonts
diff --git a/third_party/harfbuzz/tests/shaping/Makefile.am b/third_party/harfbuzz/tests/shaping/Makefile.am
new file mode 100644
index 0000000..31c6db7
--- /dev/null
+++ b/third_party/harfbuzz/tests/shaping/Makefile.am
@@ -0,0 +1,14 @@
+
+check_PROGRAMS = shaping
+
+shaping_SOURCES = main.cpp ../linebreaking/harfbuzz-qt.cpp
+shaping_LDADD = $(QT_GUI_LIBS) $(QT_QTEST_LIBS) ../../src/libharfbuzz-1.la
+
+main.o: main.moc
+
+main.moc: $(srcdir)/main.cpp
+ $(QT_MOC) -o main.moc $(srcdir)/main.cpp
+
+INCLUDES = -I$(top_srcdir)/src $(FREETYPE_CFLAGS) $(QT_GUI_CFLAGS) $(QT_QTEST_CFLAGS)
+AM_CPPFLAGS = -DQT_GUI_LIB -DSRCDIR=\"$(srcdir)\"
+
diff --git a/third_party/harfbuzz/tests/shaping/README b/third_party/harfbuzz/tests/shaping/README
new file mode 100644
index 0000000..1db1c5a
--- /dev/null
+++ b/third_party/harfbuzz/tests/shaping/README
@@ -0,0 +1,9 @@
+These shaper tests need some specific TrueType fonts. You can get a package of
+them from
+
+ http://people.freedesktop.org/~hausmann/harfbuzz-test-fonts-0.1.tar.bz2
+
+In addition you may need two fonts (Mangal and Tunga) from Microsoft Windows
+for some of the test cases. These fonts are not freely redistributable.
+
+The test program looks for them in a fonts/ subdirectory.
diff --git a/third_party/harfbuzz/tests/shaping/main.cpp b/third_party/harfbuzz/tests/shaping/main.cpp
new file mode 100644
index 0000000..1a3ef4f
--- /dev/null
+++ b/third_party/harfbuzz/tests/shaping/main.cpp
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This is part of HarfBuzz, an OpenType Layout engine library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include <QtTest/QtTest>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+
+#include <harfbuzz-shaper.h>
+#include <harfbuzz-global.h>
+#include <harfbuzz-gpos.h>
+
+static FT_Library freetype;
+
+static FT_Face loadFace(const char *name)
+{
+ FT_Face face;
+ char path[256];
+
+ strcpy(path, SRCDIR);
+ strcat(path, "/fonts/");
+ strcat(path, name);
+
+ if (FT_New_Face(freetype, path, /*index*/0, &face))
+ return 0;
+ return face;
+}
+
+static HB_UChar32 getChar(const HB_UChar16 *string, hb_uint32 length, hb_uint32 &i)
+{
+ HB_UChar32 ch;
+ if (HB_IsHighSurrogate(string[i])
+ && i < length - 1
+ && HB_IsLowSurrogate(string[i + 1])) {
+ ch = HB_SurrogateToUcs4(string[i], string[i + 1]);
+ ++i;
+ } else {
+ ch = string[i];
+ }
+ return ch;
+}
+
+static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool /*rightToLeft*/)
+{
+ FT_Face face = (FT_Face)font->userData;
+ if (length > *numGlyphs)
+ return false;
+
+ int glyph_pos = 0;
+ for (hb_uint32 i = 0; i < length; ++i) {
+ glyphs[glyph_pos] = FT_Get_Char_Index(face, getChar(string, length, i));
+ ++glyph_pos;
+ }
+
+ *numGlyphs = glyph_pos;
+
+ return true;
+}
+
+static void hb_getAdvances(HB_Font /*font*/, const HB_Glyph * /*glyphs*/, hb_uint32 numGlyphs, HB_Fixed *advances, int /*flags*/)
+{
+ for (hb_uint32 i = 0; i < numGlyphs; ++i)
+ advances[i] = 0; // ### not tested right now
+}
+
+static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
+{
+ FT_Face face = (FT_Face)font->userData;
+
+ for (hb_uint32 i = 0; i < length; ++i)
+ if (!FT_Get_Char_Index(face, getChar(string, length, i)))
+ return false;
+
+ return true;
+}
+
+static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
+{
+ FT_Face face = (FT_Face)font;
+ FT_ULong ftlen = *length;
+ FT_Error error = 0;
+
+ if (!FT_IS_SFNT(face))
+ return HB_Err_Invalid_Argument;
+
+ error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
+ *length = ftlen;
+ return (HB_Error)error;
+}
+
+HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
+{
+ HB_Error error = HB_Err_Ok;
+ FT_Face face = (FT_Face)font->userData;
+
+ int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
+
+ if ((error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags)))
+ return error;
+
+ if (face->glyph->format != ft_glyph_format_outline)
+ return (HB_Error)HB_Err_Invalid_SubTable;
+
+ *nPoints = face->glyph->outline.n_points;
+ if (!(*nPoints))
+ return HB_Err_Ok;
+
+ if (point > *nPoints)
+ return (HB_Error)HB_Err_Invalid_SubTable;
+
+ *xpos = face->glyph->outline.points[point].x;
+ *ypos = face->glyph->outline.points[point].y;
+
+ return HB_Err_Ok;
+}
+
+void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
+{
+ // ###
+ metrics->x = metrics->y = metrics->width = metrics->height = metrics->xOffset = metrics->yOffset = 0;
+}
+
+HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
+{
+ return 0; // ####
+}
+
+const HB_FontClass hb_fontClass = {
+ hb_stringToGlyphs, hb_getAdvances, hb_canRender,
+ hb_getPointInOutline, hb_getGlyphMetrics, hb_getFontMetric
+};
+
+
+//TESTED_CLASS=
+//TESTED_FILES= gui/text/qscriptengine.cpp
+
+class tst_QScriptEngine : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QScriptEngine();
+ virtual ~tst_QScriptEngine();
+
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+private slots:
+ void devanagari();
+ void bengali();
+ void gurmukhi();
+ // gujarati missing
+ void oriya();
+ void tamil();
+ void telugu();
+ void kannada();
+ void malayalam();
+ // sinhala missing
+
+ void khmer();
+ void linearB();
+};
+
+tst_QScriptEngine::tst_QScriptEngine()
+{
+}
+
+tst_QScriptEngine::~tst_QScriptEngine()
+{
+}
+
+void tst_QScriptEngine::initTestCase()
+{
+ FT_Init_FreeType(&freetype);
+}
+
+void tst_QScriptEngine::cleanupTestCase()
+{
+ FT_Done_FreeType(freetype);
+}
+
+struct ShapeTable {
+ unsigned short unicode[16];
+ unsigned short glyphs[16];
+};
+
+static bool shaping(FT_Face face, const ShapeTable *s, HB_Script script)
+{
+ QString str = QString::fromUtf16( s->unicode );
+
+ HB_Face hbFace = HB_NewFace(face, hb_getSFntTable);
+
+ HB_FontRec hbFont;
+ hbFont.klass = &hb_fontClass;
+ hbFont.userData = face;
+ hbFont.x_ppem = face->size->metrics.x_ppem;
+ hbFont.y_ppem = face->size->metrics.y_ppem;
+ hbFont.x_scale = face->size->metrics.x_scale;
+ hbFont.y_scale = face->size->metrics.y_scale;
+
+ HB_ShaperItem shaper_item;
+ shaper_item.kerning_applied = false;
+ shaper_item.string = reinterpret_cast<const HB_UChar16 *>(str.constData());
+ shaper_item.stringLength = str.length();
+ shaper_item.item.script = script;
+ shaper_item.item.pos = 0;
+ shaper_item.item.length = shaper_item.stringLength;
+ shaper_item.item.bidiLevel = 0; // ###
+ shaper_item.shaperFlags = 0;
+ shaper_item.font = &hbFont;
+ shaper_item.face = hbFace;
+ shaper_item.num_glyphs = shaper_item.item.length;
+ shaper_item.glyphIndicesPresent = false;
+ shaper_item.initialGlyphCount = 0;
+
+ QVarLengthArray<HB_Glyph> hb_glyphs(shaper_item.num_glyphs);
+ QVarLengthArray<HB_GlyphAttributes> hb_attributes(shaper_item.num_glyphs);
+ QVarLengthArray<HB_Fixed> hb_advances(shaper_item.num_glyphs);
+ QVarLengthArray<HB_FixedPoint> hb_offsets(shaper_item.num_glyphs);
+ QVarLengthArray<unsigned short> hb_logClusters(shaper_item.num_glyphs);
+
+ while (1) {
+ hb_glyphs.resize(shaper_item.num_glyphs);
+ hb_attributes.resize(shaper_item.num_glyphs);
+ hb_advances.resize(shaper_item.num_glyphs);
+ hb_offsets.resize(shaper_item.num_glyphs);
+ hb_logClusters.resize(shaper_item.num_glyphs);
+
+ memset(hb_glyphs.data(), 0, hb_glyphs.size() * sizeof(HB_Glyph));
+ memset(hb_attributes.data(), 0, hb_attributes.size() * sizeof(HB_GlyphAttributes));
+ memset(hb_advances.data(), 0, hb_advances.size() * sizeof(HB_Fixed));
+ memset(hb_offsets.data(), 0, hb_offsets.size() * sizeof(HB_FixedPoint));
+
+ shaper_item.glyphs = hb_glyphs.data();
+ shaper_item.attributes = hb_attributes.data();
+ shaper_item.advances = hb_advances.data();
+ shaper_item.offsets = hb_offsets.data();
+ shaper_item.log_clusters = hb_logClusters.data();
+
+ if (HB_ShapeItem(&shaper_item))
+ break;
+
+ }
+
+ HB_FreeFace(hbFace);
+
+ hb_uint32 nglyphs = 0;
+ const unsigned short *g = s->glyphs;
+ while ( *g ) {
+ nglyphs++;
+ g++;
+ }
+
+ if( nglyphs != shaper_item.num_glyphs )
+ goto error;
+
+ for (hb_uint32 i = 0; i < nglyphs; ++i) {
+ if ((shaper_item.glyphs[i]&0xffffff) != s->glyphs[i])
+ goto error;
+ }
+ return true;
+ error:
+ str = "";
+ const unsigned short *uc = s->unicode;
+ while (*uc) {
+ str += QString("%1 ").arg(*uc, 4, 16);
+ ++uc;
+ }
+ qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d",
+ face->family_name,
+ str.toLatin1().constData(),
+ shaper_item.num_glyphs, nglyphs);
+
+ str = "";
+ hb_uint32 i = 0;
+ while (i < shaper_item.num_glyphs) {
+ str += QString("%1 ").arg(shaper_item.glyphs[i], 4, 16);
+ ++i;
+ }
+ qDebug(" glyph result = %s", str.toLatin1().constData());
+ return false;
+}
+
+void tst_QScriptEngine::devanagari()
+{
+ {
+ FT_Face face = loadFace("raghu.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ // Ka
+ { { 0x0915, 0x0 },
+ { 0x0080, 0x0 } },
+ // Ka Halant
+ { { 0x0915, 0x094d, 0x0 },
+ { 0x0080, 0x0051, 0x0 } },
+ // Ka Halant Ka
+ { { 0x0915, 0x094d, 0x0915, 0x0 },
+ { 0x00c8, 0x0080, 0x0 } },
+ // Ka MatraI
+ { { 0x0915, 0x093f, 0x0 },
+ { 0x01d1, 0x0080, 0x0 } },
+ // Ra Halant Ka
+ { { 0x0930, 0x094d, 0x0915, 0x0 },
+ { 0x0080, 0x005b, 0x0 } },
+ // Ra Halant Ka MatraI
+ { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
+ { 0x01d1, 0x0080, 0x005b, 0x0 } },
+ // MatraI
+ { { 0x093f, 0x0 },
+ { 0x01d4, 0x029c, 0x0 } },
+ // Ka Nukta
+ { { 0x0915, 0x093c, 0x0 },
+ { 0x00a4, 0x0 } },
+ // Ka Halant Ra
+ { { 0x0915, 0x094d, 0x0930, 0x0 },
+ { 0x0110, 0x0 } },
+ // Ka Halant Ra Halant Ka
+ { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
+ { 0x0158, 0x0080, 0x0 } },
+ { { 0x0930, 0x094d, 0x200d, 0x0 },
+ { 0x00e2, 0x0 } },
+ { { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 },
+ { 0x0158, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Devanagari) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find raghu.ttf", SkipAll);
+ }
+ }
+
+ {
+ FT_Face face = loadFace("mangal.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ // Ka
+ { { 0x0915, 0x0 },
+ { 0x0080, 0x0 } },
+ // Ka Halant
+ { { 0x0915, 0x094d, 0x0 },
+ { 0x0080, 0x0051, 0x0 } },
+ // Ka Halant Ka
+ { { 0x0915, 0x094d, 0x0915, 0x0 },
+ { 0x00c8, 0x0080, 0x0 } },
+ // Ka MatraI
+ { { 0x0915, 0x093f, 0x0 },
+ { 0x01d1, 0x0080, 0x0 } },
+ // Ra Halant Ka
+ { { 0x0930, 0x094d, 0x0915, 0x0 },
+ { 0x0080, 0x005b, 0x0 } },
+ // Ra Halant Ka MatraI
+ { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 },
+ { 0x01d1, 0x0080, 0x005b, 0x0 } },
+ // MatraI
+ { { 0x093f, 0x0 },
+ { 0x01d4, 0x029c, 0x0 } },
+ // Ka Nukta
+ { { 0x0915, 0x093c, 0x0 },
+ { 0x00a4, 0x0 } },
+ // Ka Halant Ra
+ { { 0x0915, 0x094d, 0x0930, 0x0 },
+ { 0x0110, 0x0 } },
+ // Ka Halant Ra Halant Ka
+ { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 },
+ { 0x0158, 0x0080, 0x0 } },
+
+ { { 0x92b, 0x94d, 0x930, 0x0 },
+ { 0x125, 0x0 } },
+ { { 0x92b, 0x93c, 0x94d, 0x930, 0x0 },
+ { 0x149, 0x0 } },
+ { {0}, {0} }
+ };
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Devanagari) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couldn't find mangal.ttf", SkipAll);
+ }
+ }
+}
+
+void tst_QScriptEngine::bengali()
+{
+ {
+ FT_Face face = loadFace("AkaashNormal.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ // Ka
+ { { 0x0995, 0x0 },
+ { 0x0151, 0x0 } },
+ // Ka Halant
+ { { 0x0995, 0x09cd, 0x0 },
+ { 0x0151, 0x017d, 0x0 } },
+ // Ka Halant Ka
+ { { 0x0995, 0x09cd, 0x0995, 0x0 },
+ { 0x019b, 0x0 } },
+ // Ka MatraI
+ { { 0x0995, 0x09bf, 0x0 },
+ { 0x0173, 0x0151, 0x0 } },
+ // Ra Halant Ka
+ { { 0x09b0, 0x09cd, 0x0995, 0x0 },
+ { 0x0151, 0x0276, 0x0 } },
+ // Ra Halant Ka MatraI
+ { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
+ { 0x0173, 0x0151, 0x0276, 0x0 } },
+ // Ka Nukta
+ { { 0x0995, 0x09bc, 0x0 },
+ { 0x0151, 0x0171, 0x0 } },
+ // Ka Halant Ra
+ { { 0x0995, 0x09cd, 0x09b0, 0x0 },
+ { 0x01f4, 0x0 } },
+ // Ka Halant Ra Halant Ka
+ { { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 },
+ { 0x025c, 0x0276, 0x0151, 0x0 } },
+ // Ya + Halant
+ { { 0x09af, 0x09cd, 0x0 },
+ { 0x016a, 0x017d, 0x0 } },
+ // Da Halant Ya -> Da Ya-Phala
+ { { 0x09a6, 0x09cd, 0x09af, 0x0 },
+ { 0x01e5, 0x0 } },
+ // A Halant Ya -> A Ya-phala
+ { { 0x0985, 0x09cd, 0x09af, 0x0 },
+ { 0x0145, 0x01cf, 0x0 } },
+ // Na Halant Ka
+ { { 0x09a8, 0x09cd, 0x0995, 0x0 },
+ { 0x026f, 0x0151, 0x0 } },
+ // Na Halant ZWNJ Ka
+ { { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 },
+ { 0x0164, 0x017d, 0x0151, 0x0 } },
+ // Na Halant ZWJ Ka
+ { { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 },
+ { 0x026f, 0x0151, 0x0 } },
+ // Ka Halant ZWNJ Ka
+ { { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 },
+ { 0x0151, 0x017d, 0x0151, 0x0 } },
+ // Ka Halant ZWJ Ka
+ { { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 },
+ { 0x025c, 0x0151, 0x0 } },
+ // Na Halant Ra
+ { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
+ { 0x0207, 0x0 } },
+ // Na Halant ZWNJ Ra
+ { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
+ { 0x0164, 0x017d, 0x016b, 0x0 } },
+ // Na Halant ZWJ Ra
+ { { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 },
+ { 0x026f, 0x016b, 0x0 } },
+ // Na Halant Ba
+ { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
+ { 0x022f, 0x0 } },
+ // Na Halant ZWNJ Ba
+ { { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 },
+ { 0x0164, 0x017d, 0x0167, 0x0 } },
+ // Na Halant ZWJ Ba
+ { { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 },
+ { 0x026f, 0x0167, 0x0 } },
+ // Na Halant Dha
+ { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
+ { 0x01d3, 0x0 } },
+ // Na Halant ZWNJ Dha
+ { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
+ { 0x0164, 0x017d, 0x0163, 0x0 } },
+ // Na Halant ZWJ Dha
+ { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
+ { 0x026f, 0x0163, 0x0 } },
+ // Ra Halant Ka MatraAU
+ { { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 },
+ { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } },
+ // Ra Halant Ba Halant Ba
+ { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
+ { 0x0232, 0x0276, 0x0 } },
+ { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 },
+ { 0x151, 0x276, 0x172, 0x143, 0x0 } },
+ { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 },
+ { 0x151, 0x276, 0x172, 0x144, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Bengali) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find AkaashNormal.ttf", SkipAll);
+ }
+ }
+ {
+ FT_Face face = loadFace("MuktiNarrow.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ // Ka
+ { { 0x0995, 0x0 },
+ { 0x0073, 0x0 } },
+ // Ka Halant
+ { { 0x0995, 0x09cd, 0x0 },
+ { 0x00b9, 0x0 } },
+ // Ka Halant Ka
+ { { 0x0995, 0x09cd, 0x0995, 0x0 },
+ { 0x0109, 0x0 } },
+ // Ka MatraI
+ { { 0x0995, 0x09bf, 0x0 },
+ { 0x0095, 0x0073, 0x0 } },
+ // Ra Halant Ka
+ { { 0x09b0, 0x09cd, 0x0995, 0x0 },
+ { 0x0073, 0x00e1, 0x0 } },
+ // Ra Halant Ka MatraI
+ { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 },
+ { 0x0095, 0x0073, 0x00e1, 0x0 } },
+ // MatraI
+ { { 0x09bf, 0x0 },
+ { 0x0095, 0x01c8, 0x0 } },
+ // Ka Nukta
+ { { 0x0995, 0x09bc, 0x0 },
+ { 0x0073, 0x0093, 0x0 } },
+ // Ka Halant Ra
+ { { 0x0995, 0x09cd, 0x09b0, 0x0 },
+ { 0x00e5, 0x0 } },
+ // Ka Halant Ra Halant Ka
+ { { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 },
+ { 0x234, 0x24e, 0x73, 0x0 } },
+ // Ya + Halant
+ { { 0x09af, 0x09cd, 0x0 },
+ { 0x00d2, 0x0 } },
+ // Da Halant Ya -> Da Ya-Phala
+ { { 0x09a6, 0x09cd, 0x09af, 0x0 },
+ { 0x0084, 0x00e2, 0x0 } },
+ // A Halant Ya -> A Ya-phala
+ { { 0x0985, 0x09cd, 0x09af, 0x0 },
+ { 0x0067, 0x00e2, 0x0 } },
+ // Na Halant Ka
+ { { 0x09a8, 0x09cd, 0x0995, 0x0 },
+ { 0x0188, 0x0 } },
+ // Na Halant ZWNJ Ka
+ { { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 },
+ { 0xcc, 0x73, 0x0 } },
+ // Na Halant ZWJ Ka
+ { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
+ { 0x247, 0x73, 0x0 } },
+ // Ka Halant ZWNJ Ka
+ { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
+ { 0x247, 0x73, 0x0 } },
+ // Ka Halant ZWJ Ka
+ { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 },
+ { 0x247, 0x73, 0x0 } },
+ // Na Halant Ra
+ { { 0x09a8, 0x09cd, 0x09b0, 0x0 },
+ { 0x00f8, 0x0 } },
+ // Na Halant ZWNJ Ra
+ { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 },
+ { 0xcc, 0x8d, 0x0 } },
+ // Na Halant ZWJ Ra
+ { { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 },
+ { 0x247, 0x8d, 0x0 } },
+ // Na Halant Ba
+ { { 0x09a8, 0x09cd, 0x09ac, 0x0 },
+ { 0x0139, 0x0 } },
+ // Na Halant ZWNJ Ba
+ { { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 },
+ { 0xcc, 0x89, 0x0 } },
+ // Na Halant ZWJ Ba
+ { { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 },
+ { 0x247, 0x89, 0x0 } },
+ // Na Halant Dha
+ { { 0x09a8, 0x09cd, 0x09a7, 0x0 },
+ { 0x0145, 0x0 } },
+ // Na Halant ZWNJ Dha
+ { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 },
+ { 0xcc, 0x85, 0x0 } },
+ // Na Halant ZWJ Dha
+ { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 },
+ { 0x247, 0x85, 0x0 } },
+ // Ra Halant Ka MatraAU
+ { { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 },
+ { 0x232, 0x73, 0xe1, 0xa0, 0x0 } },
+ // Ra Halant Ba Halant Ba
+ { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 },
+ { 0x013b, 0x00e1, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Bengali) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find MuktiNarrow.ttf", SkipAll);
+ }
+ }
+ {
+ FT_Face face = loadFace("LikhanNormal.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x09a8, 0x09cd, 0x09af, 0x0 },
+ { 0x0192, 0x0 } },
+ { { 0x09b8, 0x09cd, 0x09af, 0x0 },
+ { 0x01d6, 0x0 } },
+ { { 0x09b6, 0x09cd, 0x09af, 0x0 },
+ { 0x01bc, 0x0 } },
+ { { 0x09b7, 0x09cd, 0x09af, 0x0 },
+ { 0x01c6, 0x0 } },
+ { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 },
+ { 0xd3, 0x12f, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Bengali) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find LikhanNormal.ttf", SkipAll);
+ }
+ }
+}
+
+void tst_QScriptEngine::gurmukhi()
+{
+ {
+ FT_Face face = loadFace("lohit.punjabi.1.1.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0xA15, 0xA4D, 0xa39, 0x0 },
+ { 0x3b, 0x8b, 0x0 } },
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Gurmukhi) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find lohit.punjabi.1.1.ttf", SkipAll);
+ }
+ }
+}
+
+void tst_QScriptEngine::oriya()
+{
+ {
+ FT_Face face = loadFace("utkalm.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
+ { 0x150, 0x125, 0x0 } },
+ { { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
+ { 0x151, 0x120, 0x0 } },
+ { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
+ { 0x152, 0x120, 0x0 } },
+ { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 },
+ { 0x152, 0x120, 0x0 } },
+ { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
+ { 0x176, 0x0 } },
+ { { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 },
+ { 0x177, 0x0 } },
+ { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 },
+ { 0x176, 0x124, 0x0 } },
+ { {0}, {0} }
+
+ };
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Oriya) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find utkalm.ttf", SkipAll);
+ }
+ }
+}
+
+
+void tst_QScriptEngine::tamil()
+{
+ {
+ FT_Face face = loadFace("akruti1.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x0b95, 0x0bc2, 0x0 },
+ { 0x004e, 0x0 } },
+ { { 0x0bae, 0x0bc2, 0x0 },
+ { 0x009e, 0x0 } },
+ { { 0x0b9a, 0x0bc2, 0x0 },
+ { 0x0058, 0x0 } },
+ { { 0x0b99, 0x0bc2, 0x0 },
+ { 0x0053, 0x0 } },
+ { { 0x0bb0, 0x0bc2, 0x0 },
+ { 0x00a8, 0x0 } },
+ { { 0x0ba4, 0x0bc2, 0x0 },
+ { 0x008e, 0x0 } },
+ { { 0x0b9f, 0x0bc2, 0x0 },
+ { 0x0062, 0x0 } },
+ { { 0x0b95, 0x0bc6, 0x0 },
+ { 0x000a, 0x0031, 0x0 } },
+ { { 0x0b95, 0x0bca, 0x0 },
+ { 0x000a, 0x0031, 0x0007, 0x0 } },
+ { { 0x0b95, 0x0bc6, 0x0bbe, 0x0 },
+ { 0x000a, 0x0031, 0x007, 0x0 } },
+ { { 0x0b95, 0x0bcd, 0x0bb7, 0x0 },
+ { 0x0049, 0x0 } },
+ { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 },
+ { 0x000a, 0x0049, 0x007, 0x0 } },
+ { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 },
+ { 0x000a, 0x0049, 0x007, 0x0 } },
+ { { 0x0b9f, 0x0bbf, 0x0 },
+ { 0x005f, 0x0 } },
+ { { 0x0b9f, 0x0bc0, 0x0 },
+ { 0x0060, 0x0 } },
+ { { 0x0bb2, 0x0bc0, 0x0 },
+ { 0x00ab, 0x0 } },
+ { { 0x0bb2, 0x0bbf, 0x0 },
+ { 0x00aa, 0x0 } },
+ { { 0x0bb0, 0x0bcd, 0x0 },
+ { 0x00a4, 0x0 } },
+ { { 0x0bb0, 0x0bbf, 0x0 },
+ { 0x00a5, 0x0 } },
+ { { 0x0bb0, 0x0bc0, 0x0 },
+ { 0x00a6, 0x0 } },
+ { { 0x0b83, 0x0 },
+ { 0x0025, 0x0 } },
+ { { 0x0b83, 0x0b95, 0x0 },
+ { 0x0025, 0x0031, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Tamil) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find akruti1.ttf", SkipAll);
+ }
+ }
+}
+
+
+void tst_QScriptEngine::telugu()
+{
+ {
+ FT_Face face = loadFace("Pothana2000.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0xc15, 0xc4d, 0x0 },
+ { 0xbb, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc37, 0x0 },
+ { 0x4b, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 },
+ { 0xe0, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 },
+ { 0x4b, 0x91, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc30, 0x0 },
+ { 0x5a, 0xb2, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 },
+ { 0xbb, 0xb2, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 },
+ { 0x5a, 0xb2, 0x83, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 },
+ { 0xe2, 0xb2, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 },
+ { 0xe6, 0xb3, 0x83, 0x0 } },
+ { { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 },
+ { 0xe6, 0xb3, 0x9f, 0x0 } },
+ { {0}, {0} }
+
+ };
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Telugu) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find Pothana2000.ttf", SkipAll);
+ }
+ }
+}
+
+
+void tst_QScriptEngine::kannada()
+{
+ {
+ FT_Face face = loadFace("Sampige.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 },
+ { 0x0049, 0x00ba, 0x0 } },
+ { { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 },
+ { 0x0049, 0x00b3, 0x0 } },
+ { { 0x0caf, 0x0cc2, 0x0 },
+ { 0x004f, 0x005d, 0x0 } },
+ { { 0x0ce0, 0x0 },
+ { 0x006a, 0x0 } },
+ { { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 },
+ { 0x006b, 0x006c, 0x006d, 0x0 } },
+ { { 0x0cb5, 0x0ccb, 0x0 },
+ { 0x015f, 0x0067, 0x0 } },
+ { { 0x0cb0, 0x0ccd, 0x0cae, 0x0 },
+ { 0x004e, 0x0082, 0x0 } },
+ { { 0x0cb0, 0x0ccd, 0x0c95, 0x0 },
+ { 0x0036, 0x0082, 0x0 } },
+ { { 0x0c95, 0x0ccd, 0x0cb0, 0x0 },
+ { 0x0036, 0x00c1, 0x0 } },
+ { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 },
+ { 0x0050, 0x00a7, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Kannada) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find Sampige.ttf", SkipAll);
+ }
+ }
+ {
+ FT_Face face = loadFace("tunga.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x0cb7, 0x0cc6, 0x0 },
+ { 0x00b0, 0x006c, 0x0 } },
+ { { 0x0cb7, 0x0ccd, 0x0 },
+ { 0x0163, 0x0 } },
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Kannada) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find tunga.ttf", SkipAll);
+ }
+ }
+}
+
+
+
+void tst_QScriptEngine::malayalam()
+{
+ {
+ FT_Face face = loadFace("AkrutiMal2Normal.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x0d15, 0x0d46, 0x0 },
+ { 0x005e, 0x0034, 0x0 } },
+ { { 0x0d15, 0x0d47, 0x0 },
+ { 0x005f, 0x0034, 0x0 } },
+ { { 0x0d15, 0x0d4b, 0x0 },
+ { 0x005f, 0x0034, 0x0058, 0x0 } },
+ { { 0x0d15, 0x0d48, 0x0 },
+ { 0x0060, 0x0034, 0x0 } },
+ { { 0x0d15, 0x0d4a, 0x0 },
+ { 0x005e, 0x0034, 0x0058, 0x0 } },
+ { { 0x0d30, 0x0d4d, 0x0d15, 0x0 },
+ { 0x009e, 0x0034, 0x0 } },
+ { { 0x0d15, 0x0d4d, 0x0d35, 0x0 },
+ { 0x0034, 0x007a, 0x0 } },
+ { { 0x0d15, 0x0d4d, 0x0d2f, 0x0 },
+ { 0x0034, 0x00a2, 0x0 } },
+ { { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 },
+ { 0x0069, 0x0 } },
+ { { 0x0d26, 0x0d4d, 0x0d26, 0x0 },
+ { 0x0074, 0x0 } },
+ { { 0x0d30, 0x0d4d, 0x0 },
+ { 0x009e, 0x0 } },
+ { { 0x0d30, 0x0d4d, 0x200c, 0x0 },
+ { 0x009e, 0x0 } },
+ { { 0x0d30, 0x0d4d, 0x200d, 0x0 },
+ { 0x009e, 0x0 } },
+
+
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Malayalam) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find AkrutiMal2Normal.ttf", SkipAll);
+ }
+ }
+}
+
+
+
+void tst_QScriptEngine::khmer()
+{
+ {
+ FT_Face face = loadFace("KhmerOS.ttf");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0x179a, 0x17cd, 0x0 },
+ { 0x24c, 0x27f, 0x0 } },
+ { { 0x179f, 0x17c5, 0x0 },
+ { 0x273, 0x203, 0x0 } },
+ { { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 },
+ { 0x275, 0x242, 0x182, 0x0 } },
+ { { 0x179a, 0x0 },
+ { 0x24c, 0x0 } },
+ { { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 },
+ { 0x274, 0x233, 0x197, 0x0 } },
+ { { 0x1798, 0x17b6, 0x0 },
+ { 0x1cb, 0x0 } },
+ { { 0x179a, 0x17b8, 0x0 },
+ { 0x24c, 0x26a, 0x0 } },
+ { { 0x1787, 0x17b6, 0x0 },
+ { 0x1ba, 0x0 } },
+ { { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 },
+ { 0x24a, 0x195, 0x26d, 0x0 } },
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Khmer) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find KhmerOS.ttf", SkipAll);
+ }
+ }
+}
+
+void tst_QScriptEngine::linearB()
+{
+ {
+ FT_Face face = loadFace("PENUTURE.TTF");
+ if (face) {
+ const ShapeTable shape_table [] = {
+ { { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 },
+ { 0x5, 0x6, 0x7, 0 } },
+ { {0}, {0} }
+ };
+
+
+ const ShapeTable *s = shape_table;
+ while (s->unicode[0]) {
+ QVERIFY( shaping(face, s, HB_Script_Common) );
+ ++s;
+ }
+
+ FT_Done_Face(face);
+ } else {
+ QSKIP("couln't find PENUTURE.TTF", SkipAll);
+ }
+ }
+}
+
+
+QTEST_MAIN(tst_QScriptEngine)
+#include "main.moc"